我只想知道“FindAll”是否比“Where”扩展方法更快,为什么?
示例:
myList.FindAll(item=> item.category == 5);
或
myList.Where(item=> item.category == 5);
哪个更好?
最佳答案
好吧,FindAll
将匹配的元素复制到一个新列表,而 Where
只返回一个延迟计算的序列 - 不需要复制。
因此,我希望 Where
比 FindAll
稍微快一点,即使结果序列已被完全评估 - 当然还有 Where 的惰性评估策略
意味着如果您只查看(比方说)第一个匹配项,则不需要检查列表的其余部分。 (正如 Matthew 指出的那样,需要维护 Where
的状态机。但是,这只会有固定的内存成本 - 而构建新列表可能需要多个数组分配等。)
基本上,FindAll(predicate)
比 Where(predicate)
更接近 Where(predicate).ToList()
。
只是为了对 Matthew 的回答做出更多 react ,我认为他的测试还不够彻底。他的谓词恰好选择了一半项。这是一个简短但完整的程序,它测试同一个列表,但使用三个不同的谓词——一个不选择任何项目,一个选择所有项目,一个选择一半。在每种情况下,我都会运行测试五十次以获得更长的时间。
我正在使用 Count()
来确保对 Where
结果进行全面评估。结果显示,收集了大约一半的结果,两者并驾齐驱。未收集到任何结果,FindAll
获胜。收集所有 结果,Where
获胜。我发现这很有趣:随着找到越来越多的匹配项,所有的解决方案都变慢了:FindAll
有更多的复制工作要做,而 Where
必须返回匹配的值而不是只是在 MoveNext()
实现中循环。但是,FindAll
比 Where
慢得多,因此失去了早期的领先优势。非常有趣。
结果:
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/