3

のより良い代替手段を探していEnumerable.Count() == nます。私が思いついた最高のものは次のとおりです。

static class EnumerableExtensions
{
    public static bool CountEquals<T>(this IEnumerable<T> items, int n)
    {
        if (n <= 0) throw new ArgumentOutOfRangeException("n"); // use Any()

        var iCollection = items as System.Collections.ICollection;
        if (iCollection != null)
            return iCollection.Count == n;

        int count = 0;
        bool? retval = null;
        foreach (var item in items)
        {
            count++;

            if (retval.HasValue)
                return false;

            if (count == n)
                retval = true;
        }

        if (retval.HasValue)
            return retval.Value;

        return false;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var items0 = new List<int>();
        var items1 = new List<int>() { 314 };
        var items3 = new List<int>() { 1, 2, 3 };
        var items5 = new List<int>() { 1, 2, 3, 4, 5 };
        var items10 = Enumerable.Range(0, 10);
        var itemsLarge = Enumerable.Range(0, Int32.MaxValue);

        Console.WriteLine(items0.CountEquals(3));
        Console.WriteLine(items1.CountEquals(3));
        Console.WriteLine(items3.CountEquals(3));
        Console.WriteLine(items5.CountEquals(3));
        Console.WriteLine(itemsLarge.CountEquals(3));
    }
}

もっとうまくできますか?これをさらに一般化する方法、つまり比較を渡す方法はありますか?

4

3 に答える 3

2

を使用Enumerable.Countすると、上記のコードよりもはるかに優れています。ICollectionすでに内部的に最適化されています。

そうは言っても、拡張機能を保持する必要がある場合は、ループを少し単純化できます。

int count = 0;
foreach (var item in items)
{
    count++;
    if(count > n)
        return false;
}
return count == n;
于 2011-02-02T00:46:33.543 に答える
2

Takeとの組み合わせを使用してCount、ループを完全に取り除くことができます。

public static bool CountEquals<T>(this IEnumerable<T> items, int n)
{
  var iCollection = items as System.Collections.ICollection;
  if (iCollection != null)
    return iCollection.Count == n;
  return items.Take(n + 1).Count() == n;
}
于 2011-02-02T01:29:19.640 に答える
0

「より良い」とは正確には何を意味しますか?もっと早く?より簡単に?

基本的に、あなたが行ったように見えるのは、特定のタスク用に最適化された特殊なメソッドを作成したことです。あなたはそれを一般化することに言及していますが、そのパフォーマンスの利点は、それが非常に具体的であるという事実に由来しています(パフォーマンスの利点があると仮定するCount、パフォーマンスのためにすでにかなりハードに調整されており、コンパイラはこのようなものを最適化するのが得意です)。

時期尚早の最適化は諸悪の根源です。この特定の操作のパフォーマンスが非常に重要であり、20 文字の式xyz.Count() == abcを数十行のコードに置き換える価値がある場合は、リファクタリングなど、パフォーマンスを向上させる他の方法を試すことができます。ほとんどの場合、マネージ コードを使用することによるオーバーヘッドだけで、得られるパフォーマンス ボーナス (あるとしても) が小さくなります。

そうは言っても、1,000 万個のアイテムがあり、ターゲット数がはるかに少ない場合、以下は反復をショートさせると確信しています。

int count = 0;
var subset = items.TakeWhile(x => count++ < n + 1);
return count == n + 1;

読みやすく、維持しやすく、おそらく同じくらい高速です。

于 2011-02-02T01:57:44.420 に答える