私はこのようなクラスを持っています:
public class MyClass
{
public int Value { get; set; }
public bool IsValid { get; set; }
}
実際にははるかに大きいですが、これは問題(奇妙さ)を再現します。
Value
インスタンスが有効なの合計を取得します。これまでのところ、これに対する2つの解決策を見つけました。
最初のものはこれです:
int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
ただし、2つ目は次のとおりです。
int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
最も効率的な方法を取得したいと思います。最初は、2番目のほうが効率的だと思いました。それから私の理論的な部分は「まあ、1つはO(n + m + m)、もう1つはO(n + n)です。最初の1つは無効が多いほどパフォーマンスが良く、2つ目はパフォーマンスが高いはずです。より少ない」。それらは同等に機能すると思いました。編集:そして@MartinはWhereとSelectが組み合わされていることを指摘したので、実際にはO(m + n)になるはずです。ただし、以下を見るとこれは関係ないようです。
だから私はそれをテストにかけました。
(100行以上なので、要旨として投稿した方がいいと思いました。)
結果は...興味深いものでした。
0%のタイ許容差で:
スケールは、約30ポイントでSelect
とWhere
に支持されています。
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36
2%のタイ許容差で:
同じですが、2%以内に収まるものもありました。これが最小の誤差範囲だと思います。Select
そしてWhere
今、わずか20ポイントのリードがあります。
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37
5%のタイ許容差で:
これが私の最大の誤差範囲であると私は言うでしょう。それはにとっては少し良くなりますがSelect
、多くはありません。
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31
10%のタイ許容差で:
これは私の誤差の範囲外ですが、私はまだ結果に興味があります。それが与えるのでSelect
そしてWhere
それは今しばらく持ったという20ポイントのリード。
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21
25%のタイ許容差で:
これは道であり、道エラーの私のマージンのうち、しかし、ので、私は今でも、結果に興味があるSelect
し、Where
まだ(ほぼ)その20ポイントのリードを保ちます。いくつかの点でそれを上回っていると思われ、それが主導権を握っています。
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0
今、私は20ポイントのリードは、それらが両方得るためにバインドされている途中、から来たことを推測しているの周りに同じ性能を。試してログに記録することはできますが、それを取り込むには大量の情報が必要になります。グラフの方がいいと思います。
それが私がしたことです。
これは、Select
ラインが安定している(予想される)ことと、Select + Where
ラインが上昇する(予想される)ことを示しています。それはと合致しない理由しかし、何を私に困惑することでSelect
、余分な列挙子がために作成されなければならなかったとして、実際に私は、以前の50よりも期待していた:50またはそれ以前のバージョンでSelect
とWhere
。つまり、これは20ポイントのリードを示していますが、その理由を説明していません。これが私の質問の要点だと思います。
なぜこのように動作するのですか?信用すべきでしょうか?そうでない場合は、もう一方またはこれを使用する必要がありますか?
コメントで@KingKongが言及したように、Sum
ラムダをとるのオーバーロードを使用することもできます。したがって、私の2つのオプションは次のように変更されます。
最初:
int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
第二:
int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);
少し短くしますが、次のようにします。
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where: 60
Sum: 41
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 8
Where: 55
Sum: 38
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 21
Where: 49
Sum: 31
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 39
Where: 41
Sum: 21
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where: 16
Sum: 0
20ポイントのリードはまだあります。つまり、コメントで@Marcinによって指摘されたWhere
とのSelect
組み合わせとは関係ありません。
テキストの壁を読んでいただきありがとうございます。あなたが興味を持っている場合も、ここだ ExcelがでとることCSVをログに記録します修正版。
Where
+ Select
は、入力コレクションに対して2つの分離された反復を引き起こしません。LINQ to Objectsは、それを1つの反復に最適化します。私のブログ投稿の
mc.Value
。