【问题标题】:LINQ Count() until, is this more efficient?LINQ Count() 直到,这更有效吗?
【发布时间】:2012-03-09 01:21:01
【问题描述】:

假设我想检查一个集合中是否至少有 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;
    }

【问题讨论】:

  • 我如何对此进行基准测试? - 将您通常用来调用它们的代码放入一个带计时的循环中......
  • 另一个选项:enumerable.Select((o, idx) => idx).Any(i => i >= max);

标签: c# performance linq ienumerable micro-optimization


【解决方案1】:

.Count() 方法内置了一些有据可查的优化。具体来说,如果您的枚举是ICollection.Count() 将是一个常量时间操作,因为它将使用ICollection.Count 属性。

但是,在一般情况下,它将迭代整个 IEnumerable 以获取计数。如果您没有ICollection,那么当元素数超过 N 时,最好使用您建议的两种方法中的任何一种。对于这两者的相对表现,您必须按照其他人的建议对它们进行概要分析。

【讨论】:

  • 我会警惕他的实现。我们是否保证任何 Linq 方法在写入这样的外部变量时都是线程安全的?如果它依次遍历IEnumerable&lt;T&gt; 应该没问题。但是,如果在任何时候都可能有多个线程并行评估它,那可能是错误的定义。
  • @Mike:至少我认为.Take(n) 方法会很好——毕竟,它只是迭代可枚举并在达到n 元素或整个集合之后停止被迭代(如果IEnumerable 中的元素少于n)。我不确定.Any() 方法的线程安全性。
【解决方案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

【讨论】:

  • 这甚至没有意义,使用一个你知道Count 是100000 的列表,并且不需要调用任何方法。仅使用 enumerable.range 而不使用列表的结果是什么?
  • Nico,好点 :) 更新了答案以仅使用 Enumerable.Range 来反映结果。
  • 将 .ToList() 添加到 Enumerable.Range 的末尾,您的 list.Count() 操作将是最好的。
猜你喜欢
  • 2011-07-23
  • 1970-01-01
  • 2014-08-19
  • 1970-01-01
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
相关资源
最近更新 更多