2009-07-01 7 views
2

私はC++のコードでいくつかのコーディングをしています。私が扱っていることの多くはデータセットの解析に関係しています。非常に多くの場合、私は、STLコンテナからのいくつかの要素を選択する必要があり、非常に頻繁に私はこのようなコードを書いた:命令言語でSQLを選択する

using std::vector; 
vector<int> numbers; 
for (int i = -10; i <= 10; ++i) { 
    numbers.push_back(i); 
} 

vector<int> positive_numbers; 
for (vector<int>::const_iterator it = numbers.begin(), end = numbers.end(); 
     it != end; ++it 
) { 
    if (number > 0) { 
     positive_numbers.push_back(*it); 
    } 
} 

ループとそれに含まれるロジックのための多くは、より複雑で読めなくなります。この時間が経ちます。

SELECT * INTO positive_numbers FROM numbers WHERE num > 0 

たくさんあります。このようなコードは、私はむしろSTDよりも「NUM」という名前の列::ベクトルで<整数>をテーブルと呼ばれる数字を持っていると仮定して、SQLで類似のSELECT文未満満足ですより読みやすく、スケーラビリティが向上しました。コードベースにあるif文のロジックの多くは複雑で、順序に依存し、維持不能になっています。私たちがデータベースに行かなくてもC++でSQLのようなステートメントを実行できれば、コードの状態がより良いかもしれないと思います。

C++でSELECT文のようなものを実装できる簡単な方法はありますか?どこのオブジェクトの特性だけを記述してオブジェクトの新しいコンテナを作成できますか?私はまだC++には比較的新しいので、テンプレートのメタプログラミングやこれを解決する巧妙なイテレータの魔法があることを期待しています。ありがとう!

最初の2つの回答に基づいて編集します。ありがとう、私はそれが実際にLINQだったことを知らなかった。主にLinuxとOSXシステムでプログラムを作成し、OSX、Linux、Windowsのクロスプラットフォームに関心があります。 C++のためのLINQのようなものをクロスプラットフォームで実装しているのでしょうか?

答えて

2

LINQは、Windows以外のプラットフォーム上で.NET(またはモノラルのための明白な答えですが、C++で、その困難はSTLでそれを自分のようなものを書くことではありません。

使用Boost.Iterator 「選択」イテレータを書くためのライブラリーは、例えば、与えられた述語を満たさないすべての要素をスキップします1。

ブーストは、すでに私は信じている彼らのドキュメントのいくつかの関連する例があります。 かhttp://www.boost.org/doc/libs/1_39_0/libs/iterator/doc/filter_iterator.htmlが実際に何をあなたを行う可能性があります

いずれにしても、C++では、基本的にイテレータを重ねることで同じ効果が得られます。

シーケンス内のすべての要素にアクセスする通常のイテレータがある場合は、フィルタイテレータでその要素をラップすることができます。フィルタイテレータは、条件を満たす値が見つかるまで、そのイテレータをインクリメントします。次に、値を目的の形式に変換する「選択」イテレータでラップすることもできます。

これはかなり明白なアイデアのようですが、私はそれを完全に実装しているわけではありません。

+0

ありがとう。私はすでにこのために実装されていた魔法を探していましたが、イテレータとフィルタを使用してあなたの提案を試してみる可能性があります。 –

3

LINQ(C#と.NET 3.5の機能)について説明したと思います。それを調べましたか?

+0

これは.NETの機能なので、C++から使用できます。 –

4

あなたはほぼ正確にLINQを記述しました。これは.NET 3.5の機能なので、C++から使用できるはずです。

4

など

あなたは一般的に、このような閉鎖、述語、ファンクタような概念をサポートして関数型言語で発見された記述している機能は、上記のコードの問題は、それが結合していることである:

  1. コレクションを反復するためのロジック(forループ)
  2. 要素を別のコレクションにコピーするために満たす必要がある条件
  3. あるコレクションから別のコレクションに要素をコピーするロジック

実際には、(1)と(3)は定型文です。コレクションの一部を別のコレクションにコピーする必要があるたびに、おそらく毎回変更される条件付きコードだけです。関数型プログラミングをサポートする言語はこの定型文を排除します。例えば、GroovyであなたはC++でSTLのコレクションで機能的なスタイルのプログラミングのためのサポートを提供するライブラリがあるかもしれない関数型言語ではありませんが、単に

def positive_numbers = numbers.findAll{it > 0} 

して上記ループのためにあなたを置き換えることができます。たとえば、Apacheコモンズコレクション(場合によってはGoogleのコレクションライブラリ)は、Java自体が機能的な言語ではないにもかかわらず、Javaコレクションによる機能スタイルのプログラミングをサポートしています。

0

Linux/OS X上でLINQを試してみたい場合は、Monoをチェックしてください。これは.NET Frameworkのポートであり、LINQが含まれています。

1

あなたはSTLコンテナを使用しています。私はSTL algorithmsを使用することをお勧めします。 SQL selectは、std::find_ifの繰り返しアプリケーション、またはstd::lower_boundstd::upper_bound(ソートされたコンテナ)の組み合わせに変換されます。パフォーマンスはループとほぼ同じですが、構文はもう少し宣言的です。

LINQは同様の構文と操作を行いますが、IQueryable(すなわちデータベース内のデータ)を超えて使用しない限り、パフォーマンスの向上は得られません。

あなたの最善の策は、このようなことのためにファイルに物を入れていることです。それはBerkelyDBNetCDFHDF5STXXLなどです。ファイルへのアクセスは遅いですが、これを行うと、メモリに収まるよりも多くのデータを扱うことができます。

1

std :: vectorはとても良い選択ではありません。これは、インデックスのないテーブルと同等のSQLです。それに加えて、あるコンテナに別のコンテナの内容を書き込むことは、合理的なパフォーマンスの最適化ですが、あまり読みにくくなく、あまり慣れないものでもあります。これを移植可能(IE、マネージドコードに頼らずに解決する方法)がいくつかあります.net

最初の選択肢は、より良いコンテナを選択することです。安定した反復処理が必要ない場合は、std :: setまたはstd :: multi_setを使用する必要があります。これらのコンテナはバランスの取れた検索ツリーを使用して値を順番に格納します。これは、すべての列の単純なSQL索引に相当します。

std::set<int> numbers; 
for (int i = -10; i <= 10; ++i) { 
    numbers.insert(i); 
} 

std::set::iterator first = numbers.find(1); 
std::set::iterator end = numbers.end(); 

今、あなたはが求める(N)(ログ)塗りつぶしとO()N(ログ)O上で、余分な労力を無駄にすることなくendまでfirstから繰り返すことができます。反復処理は、(1)あなたは、ベクターを使用しなければならない何らかの理由で、あなたはより多くの慣用的なC++ std::find_ifを使用して取得することができ、場合あなたも何かをしたい場合はstd::set::iterator

bool isPositive(int n) { return n > 0; } 

std::vector<int> numbers; 
for (int i = -10; i <= 10; ++i) { 
    numbers.push_back(i); 
} 

for (std::vector<int>::const_iterator end = numbers.end(), 
     iter = std::find_if(numbers.begin(), end, isPositive); // <- first positive value 
     iter != end; 
     iter = std::find_if(iter, end, isPositive) // <- advance iter to the next positive 
) { 

    // iter is guaranteed to be positive here, do something with it! 
} 

を(Max Lybbert's答えを参照)Oであります実際にデータベースに接続せずにSQLをより喚起するには、Boost、特にboost::multi_indexのコンテナとブーストイテレータを参照する必要があります。

関連する問題