C ++のオブジェクトへのLINQ

それはすべて、私が研究所にいたときから始まり、卒業後、C ++でコードを記述し、トラブルを知りませんでした。 しかし、ある日、C#で.NETのコードを書く必要がありました。 最初は少し吐きましたが、その後は何もしませんでした-彼は関与しました。 C ++との有益な違いを見ました:セキュリティ、厳密さなど。 また、コレクションを操作するときにLINQを無視できませんでした...



問題の紹介


しかし、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の外観とは異なって見えました。 その瞬間、私は自分自身に強さを感じました-私の実装を書き、テストでそれをカバーすること。

私の主なタスクは次のとおりです。


これが、 boolinqプロジェクトの由来です(この名前はboollinqという単語を組み合わせたものです)。 Google Code: http : //code.google.com/p/boolinq/に投稿しました。 そして、ここに私が得たものがあります:

 int sum = boolinq::from(cnadles).sum([](Candle c){return c.ClosePrice;}); 

もちろん、LINQよりも少し複雑に見えます。 ただし、これはC ++のラムダ式の構文のみによるものです。 コードの構造自体は変わりません。 現在、次の機能が実装されています。

シーケンス変換:

シーケンスアグリゲーター:

エクスポートシーケンス:

そして、いくつかの珍しいものでさえ:


使用例


式の例を次に示します。

 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

Source: https://habr.com/ru/post/J142632/


All Articles