2012-03-09 11 views
12

私はコレクションにN個以上の要素があるかどうかチェックしたいと思います。LINQ Count()until、これはより効率的ですか?

これはこれよりも優れていますか?

Count() >= N

使用:

public static bool AtLeast<T>(this IEnumerable<T> enumerable, int max) 
    { 
     int count = 0; 
     return enumerable.Any(item => ++count >= max); 
    } 

あるいは

public static bool Equals<T>(this IEnumerable<T> enumerable, int amount) 
    { 
     return enumerable.Take(amount).Count() == amount; 
    } 

どのように私のベンチマークこれだろうか?

/// <summary> 
    /// Returns whether the enumerable has at least the provided amount of elements. 
    /// </summary> 
    public static bool HasAtLeast<T>(this IEnumerable<T> enumerable, int amount) 
    { 
     return enumerable.Take(amount).Count() == amount; 
    } 

    /// <summary> 
    /// Returns whether the enumerable has at most the provided amount of elements. 
    /// </summary> 
    public static bool HasAtMost<T>(this IEnumerable<T> enumerable, int amount) 
    { 
     return enumerable.Take(amount + 1).Count() <= amount; 
    } 
+3

を_HowベンチマークIでしこれ_ - あなたは、通常のタイミングでループ内でそれらを呼び出すために使用したいコードを入れて..? –

+0

別のオプション: enumerable.Select((o、idx)=> idx).Any(i => i> = max); – KristoferA

答えて

5

.Count()メソッドには、文書化された最適化が組み込まれています。具体的には、列挙型がICollectionの場合、ICollection.Countプロパティを使用するため、.Count()は一定時間操作になります。

しかし、一般的なケースでは、IEnumerable全体を反復してカウントを取得します。 ICollectionがない場合は、N個以上の要素がある場合は、2つの方法のいずれかを使用する方がよいでしょう。これらの2つの相対的なパフォーマンスについては、他の人が示唆しているようにプロファイルする必要があります。 PrintTimeは()タイマーを出力

+0

私は彼の実装については気をつけたいと思います。 Linqメソッドは、そのような外部変数への書き込みでスレッドセーフであることが保証されていますか? 'IEnumerable 'を順番にたどる場合は、順調であるはずです。しかし、いつでも複数のスレッドを並列に評価することができれば、それはあまり定義されていない可能性があります。 –

+0

@Mike:少なくとも '.Take(n) 'アプローチはうまくいくと思います。結局のところ、列挙型を反復していて、' n'要素に達した後、またはコレクション全体が反復された'IEnumerable'に' n'よりも少ない要素がある場合)。私は '.Any()'アプローチのスレッドセーフについてはわかりません。 – goric

2
 var list = Enumerable.Range(1, 1000000); 
     var t = new Stopwatch(); 

     t.Restart(); 
     var count = list.Count() > 100000; 
     t.Stop(); 
     PrintTime(t, count); 

     t.Restart(); 
     var atLeast = list.AtLeast(100000); 
     t.Stop(); 
     PrintTime(t, atLeast); 

     t.Restart(); 
     var equals = list.Equalss(100000); 
     t.Stop(); 
     PrintTime(t, equals); 

結果はダニ:

True 20818 
True 8774 
True 8688 
+1

これは意味をなさない。あなたが知っているリストを使って、「Count」が100000であり、何のメソッドも呼び出す必要はないということを知っている。リストなしでenumerable.rangeだけを使用してあなたの不満は何ですか? – bevacqua

+0

Nico、良い点:) Enumerable.Rangeだけを使用して結果を反映するように更新されました。 – Beyers

+0

+1実際のタイミングを与える。 – jwg

関連する問題