![](https://habrastorage.org/storage2/cba/9b9/149/cba9b9149efae1b653e6b302015e39e5.jpg)
問題の紹介
しかし、C ++に戻るときが来たとき、LINQのすべての魅力に感謝しました。 6か月の休憩の後、C ++で書くのは少し珍しいことでした。 突然、ベクトルの要素の合計、より具体的にはベクトルの要素のフィールドの合計を計算しなければならなかったとき、何も悪いことはありませんでした。 C#では、これは次のように解決されます。
int sum = candles.Sum(c => c.ClosePrice);
しかし、C ++では次のようになりました。
int sum = 0; for(int i = 0; i < candles.size(); i++) sum += candles[i].ClosePrice;
そして、イテレータを書き直すと:
int sum = 0; for(auto it = candles.begin(); it != candles.end(); ++it) sum += it->ClosePrice;
Qtは物事を少しだけ簡単にしますが、それほど多くはしません:
int sum = 0; foreach(Candle candle, candles) sum += candle.ClosePrice;
また、新しいC ++ 11言語標準は簡素化を約束し、
しかし、Visual Studio 2010
int sum = 0; for (Candle candle : vector) sum += candle.ClosePrice;
あなたはすぐに善に慣れます。 それは完全な混乱でした。 これらのオプションはすべて私には向いていませんでした。 1行のソリューションが必要でした。 その後、私はグーグルを始め、最初のリンクで見つけました: http : //stackoverflow.com/questions/3221812/sum-of-elements-in-a-stdvector
提案されたソリューションの最短:
int sum = std::accumulate(vector.begin(), vector.end(), 0);
ただし、フィールドの1つだけの値を追加する必要がある場合はどうすればよいでしょうか。 もちろん、逆参照されたときにフィールドの1つを返す巧妙なイテレータを作成することもできます...しかし、これはすべて、このような単純なタスクのハードコーディングのようなにおいがします。
どうする?
次の20〜30分間のグーグル検索では、 ブースト範囲と他のいくつかのライブラリがあることが示されましたが、それらはすべてLINQの外観とは異なって見えました。 その瞬間、私は自分自身に強さを感じました-私の実装を書き、テストでそれをカバーすること。
私の主なタスクは次のとおりです。
- ライブラリをできるだけLINQに似たものにします
- すべての機能を「遅延」させる(遅延)
これが、 boolinqプロジェクトの由来です(この名前はboolとlinqという単語を組み合わせたものです)。 Google Code: http : //code.google.com/p/boolinq/に投稿しました。 そして、ここに私が得たものがあります:
int sum = boolinq::from(cnadles).sum([](Candle c){return c.ClosePrice;});
もちろん、LINQよりも少し複雑に見えます。 ただし、これはC ++のラムダ式の構文のみによるものです。 コードの構造自体は変わりません。 現在、次の機能が実装されています。
シーケンス変換:
- 取る(int)
- スキップ(int)
- concat(範囲)
- ここで(ラムダ)
- 選択(ラムダ)
- 逆()
- orderBy()
- orderBy(ラムダ)
- groupBy(ラムダ)
- 明確な()
- 異なる(ラムダ)
- for_each(ラムダ)
シーケンスアグリゲーター:
- すべて()
- すべて(ラムダ)
- いずれか()
- 任意(ラムダ)
- 合計()
- 合計(ラムダ)
- 平均()
- 平均(ラムダ)
- 分()
- 分(ラムダ)
- 最大()
- 最大(ラムダ)
- カウント()
- カウント(ラムダ)
- 含む(値)
- elementAt(int)
エクスポートシーケンス:
- toSet()
- toList()
- toDeque()
- toVector()
- toContainer <T>()
そして、いくつかの珍しいものでさえ:
- バイト()
- バイト<ByteOrder>()
- unbytes <T>()
- unbytes <T、ByteOrder>()
- ビット()
- ビット<BitOrder>()
- ビット<BitOrder、ByteOrder>()
- アンビット()
- unbits <BitOrder>()
- unbits <T>()
- unbits <T、BitOrder>()
- unbits <T、BitOrder、ByteOrder>()
使用例
式の例を次に示します。
int src[] = {1,2,3,4,5,6,7,8}; auto dst = from(src).where( [](int a){return a%2 == 1;}) // 1,3,5,7 .select([](int a){return a*2;}) // 2,6,10,14 .where( [](int a){return a>2 && a<12;}) // 6,10 .toVector();
いくつかの操作は、元のコレクションに段階的に適用されます。
1.奇数の値を持つ要素のみを残します。
2.各要素の値に2を掛けます。
3.範囲(2,12)の値を持つアイテムのみを残します。
4.結果は
std::vector
配置されます。
または、より複雑な式:
struct Man { std::string name; int age; }; Man src[] = { {"Kevin",14}, {"Anton",18}, {"Agata",17}, {"Terra",20}, {"Layer",15}, }; auto dst = from(src).where( [](const Man & man){return man.age < 18;}) .orderBy([](const Man & man){return man.age;}) .select( [](const Man & man){return man.name;}) .toVector();
dst
変数の型は
std::vector<std::string>
ます。 結果のベクトルには、「Kevin」、「Layer」、「Agata」の値が含まれます。 ソース配列に適用されるアクション:
1. 18歳未満の人だけを配列に残します。
2.経過時間を長くすることにより、配列内の要素を配置します。
3.配列から名前のみを選択します。
4.結果は
std::vector
配置されます。
おわりに
結果は、配列、ベクトル、およびその他のデータコンテナに対する遅延クエリのライブラリです。 関数の速度は、ループを使用して記述された同様のプログラムの速度に劣りません。 構文は、LINQにできるだけ近いものにします。 ライブラリの機能の設計と開発に時間を費やしました。 コードはテストで十分にカバーされています(何パーセントかはわかりません。誰かから教えられたら嬉しいです)。 LINQには類似物がない関数があります。
ライブラリは、単一のヘッダーファイル
boolinq-all.h
として配布されます。 誰かがこのライブラリが便利だと思ったら嬉しいです。 機能を追加して改善の提案がある場合は、声をかけてください。 時間と時間を過ごしたい場合は、参加してください。 誰でもGoogle Codeのコードにコメントを残すことができます。 Googleグループでディスカッショングループも作成されました: https : //groups.google.com/forum/?fromgroups#! forum/ boolinq