c# - FindAll 与 Where 扩展方法

标签 c# lambda extension-methods

我只想知道“FindAll”是否比“Where”扩展方法更快,为什么?

示例:

myList.FindAll(item=> item.category == 5);

myList.Where(item=> item.category == 5);

哪个更好?

最佳答案

好吧,FindAll 将匹配的元素复制到一个新列表,而 Where 只返回一个延迟计算的序列 - 不需要复制。

因此,我希望 WhereFindAll 稍微快一点,即使结果序列已被完全评估 - 当然还有 Where 的惰性评估策略 意味着如果您只查看(比方说)第一个匹配项,则不需要检查列表的其余部分。 (正如 Matthew 指出的那样,需要维护 Where 的状态机。但是,这只会有固定的内存成本 - 而构建新列表可能需要多个数组分配等。)

基本上,FindAll(predicate)Where(predicate) 更接近 Where(predicate).ToList()

只是为了对 Matthew 的回答做出更多 react ,我认为他的测试还不够彻底。他的谓词恰好选择了一半项。这是一个简短但完整的程序,它测试同一个列表,但使用三个不同的谓词——一个不选择任何项目,一个选择所有项目,一个选择一半。在每种情况下,我都会运行测试五十次以获得更长的时间。

我正在使用 Count() 来确保对 Where 结果进行全面评估。结果显示,收集了大约一半的结果,两者并驾齐驱。未收集到任何结果,FindAll 获胜。收集所有 结果,Where 获胜。我发现这很有趣:随着找到越来越多的匹配项,所有的解决方案都变慢了:FindAll 有更多的复制工作要做,而 Where 必须返回匹配的值而不是只是在 MoveNext() 实现中循环。但是,FindAllWhere 慢得多,因此失去了早期的领先优势。非常有趣。

结果:

FindAll: All: 11994
Where: All: 8176
FindAll: Half: 6887
Where: Half: 6844
FindAll: None: 3253
Where: None: 4891

(使用/o+/debug- 编译并从命令行运行,.NET 3.5。)

代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

class Test
{
    static List<int> ints = Enumerable.Range(0, 10000000).ToList();

    static void Main(string[] args)
    {
        Benchmark("All", i => i >= 0); // Match all
        Benchmark("Half", i => i % 2 == 0); // Match half
        Benchmark("None", i => i < 0); // Match none
    }

    static void Benchmark(string name, Predicate<int> predicate)
    {
        // We could just use new Func<int, bool>(predicate) but that
        // would create one delegate wrapping another.
        Func<int, bool> func = (Func<int, bool>) 
            Delegate.CreateDelegate(typeof(Func<int, bool>), predicate.Target,
                                    predicate.Method);
        Benchmark("FindAll: " + name, () => ints.FindAll(predicate));
        Benchmark("Where: " + name, () => ints.Where(func).Count());
    }

    static void Benchmark(string name, Action action)
    {
        GC.Collect();
        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < 50; i++)
        {
            action();
        }
        sw.Stop();
        Console.WriteLine("{0}: {1}", name, sw.ElapsedMilliseconds);
    }
}

关于c# - FindAll 与 Where 扩展方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1531702/

相关文章:

c# - 将 Lambda LINQ 语句作为 Func<> 传递时出现问题

c# - 将 DbSet 传递给参数类型为 IEnumerable<> 的方法时出现奇怪的 EF 行为

c++ - 在 lambda 比较器中使用捕获

Java 8 - 如何使用具有参数函数的谓词?

c# - 限制通用扩展方法扩展字符串

c# - 扩展方法不可见

c# - Linq to Sql 多一关系

c# - c#中枚举元素的默认值?

c# - 我可以为 RabbitMQ 消费者设置明确的任务超时吗?

c# - 是否可以为抽象类编写扩展方法