5

この質問はこれに関連してますが、完全に同じではないと思います

与えられた:

class Foo
{
  public string Bar { get; set; }
}
...
var c1 = new List<Foo>() { ... };
var c2 = new List<Foo>() { ... };

次の 2 つのループは同じ結果になります。

  foreach (var item in c2.Where(f => c1.Any(f1 => f1.Bar.Equals(f.Bar))))
  { ... }

  foreach (var item in c2.Where(f => c1.Select(f1 => f1.Bar).Contains(f.Bar)))
  { ... }

それらは同じように速いですか?

他の質問との違いは、ここでの余分なSelectステートメントが、基になるコレクションの性質の重要性を変えるかどうかです。

言い換えれば:これは含まれていますか:

foos.Contains(foo1)

これと同じ「種類のコレクション」で動作します。

foos.Select(f=>f.Bar).Contains(foo1.Bar)

私の考えられる素朴な考えは次のとおりです。

4

2 に答える 2

18

両方のクエリは、基本的に同じアルゴリズムを実装しています。c1これらはの各アイテムに対してそれぞれ反復し、2 つのオブジェクトc2のプロパティを比較しBarて、一致が見つかるとすぐに戻ります。2 つのケースの漸近的な複雑さは同じです。つまり、2 つのセットのサイズが大きくなるにつれて、どちらも同じようにうまくスケーリングします (場合によっては、同じように悪くなります)。

一方のメソッドと他方のメソッドに関連するオーバーヘッドには、この 2 つの間に小さな違いがあるかもしれませんが、大きな違いはなく、コレクションのサイズが大きくなるにつれて、それらのメソッドはどんどん小さくなります。2 つのうちの 1 つを選択する実際のパフォーマンス上の理由はありません。

これらのいずれよりもかなり高速な、表示されていないオプションがあります。a を使用して、シーケンス全体を線形検索せずに にも存在するJoinすべてのアイテムを見つけることができます。c1c2

var query = from first in c1
    join second in c2
    on first.Bar equals second.Bar
    select first;

別のオプションは、より簡単に検索できるため、 a のHashSet代わりに aを使用することです。List

var set = new HashSet<string>(c1.Select(item => item.Bar));

var query = c2.Where(item => set.Contains(item.Bar));

Join(このソリューションは、内部的に行うものにかなり近いものです。)

これらのソリューションは両方とも、提案されたソリューションのいずれよりもはるかに高速になります。

于 2013-06-25T16:24:23.353 に答える
0

最初のアプローチは、1 回反復して比較し、結果を返します。

Bar2 番目のクエリは、反復してプロパティをコレクションに抽出し、反復して比較しf.Barて最終結果を作成するため、処理が遅くなります。

于 2013-06-25T16:09:41.440 に答える