LINQ Count()直到,这样做是否更有效率?

11

假设我想要检查一个集合中是否至少有N个元素。

这个比使用以下代码会更好吗?

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
我该如何进行基准测试?- 将您通常用于调用它们的代码放入一个带有计时的循环中... - M.Babcock
另一种选择: enumerable.Select((o, idx) => idx).Any(i => i >= max); - KristoferA
2个回答

5
< p > .Count()方法中内置了一些经过充分记录的优化措施。特别地,如果您的可枚举对象是一个ICollection,那么.Count()将成为一个常数时间操作,因为它会使用ICollection.Count属性。

然而,在一般情况下,它将遍历整个IEnumerable以获取计数。如果您没有ICollection,当元素数量超过N时,最好使用您提出的两种方法之一。至于这两种方法的相对性能,您需要像其他人建议的那样进行分析。


我会对他的实现持谨慎态度。我们能保证像这样写入外部变量的任何Linq方法都是线程安全的吗?如果它按顺序遍历IEnumerable<T>,那应该没问题。但是如果在任何时候可能有多个线程并行评估它,那可能就不明确了。 - Mike Bailey
@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);

PrintTime()打印计时器滴答声的结果:

True 20818
True 8774
True 8688

1
这甚至没有意义,使用列表,您知道Count为100000,不需要调用任何方法。如果只使用Enumerable.Range而不使用列表,您的结果是什么? - bevacqua
Nico,好观点 :) 更新答案以反映只使用Enumerable.Range的结果。 - Beyers
在 Enumerable.Range 的末尾添加 .ToList(),你的 list.Count() 操作将变得更加高效。 - Michael Brown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接