FindAll 与 Where 扩展方法 [英] FindAll vs Where extension-method
问题描述
我只想知道FindAll"是否会比Where"扩展方法更快,为什么?
I just want know if a "FindAll" will be faster than a "Where" extentionMethod and why?
示例:
myList.FindAll(item=> item.category == 5);
或
myList.Where(item=> item.category == 5);
哪个更好?
推荐答案
好吧,FindAll
将匹配的元素复制到一个新列表中,而 Where
只是返回一个懒惰的计算结果序列 - 不需要复制.
Well, FindAll
copies the matching elements to a new list, whereas Where
just returns a lazily evaluated sequence - no copying is required.
因此我希望 Where
比 FindAll
稍微快一点,即使结果序列被完全评估 - 当然还有 Where 的惰性评估策略
意味着如果您只查看(例如)第一个匹配项,则不需要检查列表的其余部分.(正如 Matthew 指出的那样,需要维护 Where
的状态机.但是,这只会有固定的内存成本 - 而构建新列表可能需要多个数组分配等.)
I'd therefore expect Where
to be slightly faster than FindAll
even when the resulting sequence is fully evaluated - and of course the lazy evaluation strategy of Where
means that if you only look at (say) the first match, it won't need to check the remainder of the list. (As Matthew points out, there's work in maintaining the state machine for Where
. However, this will only have a fixed memory cost - whereas constructing a new list may require multiple array allocations etc.)
基本上,FindAll(predicate)
更接近于 Where(predicate).ToList()
而不是 Where(predicate)
.
Basically, FindAll(predicate)
is closer to Where(predicate).ToList()
than to just Where(predicate)
.
只是为了对 Matthew 的回答做出更多反应,我认为他的测试还不够彻底.他的谓词恰好选择了一半的项目.这是一个简短但完整的程序,它测试相同的列表,但具有三个不同的谓词 - 一个不选择项目,一个选择所有项目,一个选择一半.在每种情况下,我都运行了 50 次测试以获得更长的时间.
Just to react a bit more to Matthew's answer, I don't think he's tested it quite thoroughly enough. His predicate happens to pick half the items. Here's a short but complete program which tests the same list but with three different predicates - one picks no items, one picks all the items, and one picks half of them. In each case I run the test fifty times to get longer timing.
我正在使用 Count()
来确保对 Where
结果进行完全评估.结果显示,收集到一半左右的结果,两者并驾齐驱.没有收集结果,FindAll
获胜.收集所有结果,Where
获胜.我觉得这很有趣:随着找到越来越多的匹配项,所有解决方案都变得更慢:FindAll
需要进行更多的复制,而 Where
必须返回匹配的值而不是只是在 MoveNext()
实现中循环.但是,FindAll
的速度比 Where
慢,因此失去了早期的领先优势.很有趣.
I'm using Count()
to make sure that the Where
result is fully evaluated. The results show that collecting around half the results, the two are neck and neck. Collecting no results, FindAll
wins. Collecting all the results, Where
wins. I find this intriguing: all of the solutions become slower as more and more matches are found: FindAll
has more copying to do, and Where
has to return the matched values instead of just looping within the MoveNext()
implementation. However, FindAll
gets slower faster than Where
does, so loses its early lead. Very interesting.
结果:
FindAll: All: 11994
Where: All: 8176
FindAll: Half: 6887
Where: Half: 6844
FindAll: None: 3253
Where: None: 4891
(使用/o+/debug- 编译并从命令行运行,.NET 3.5.)
(Compiled with /o+ /debug- and run from the command line, .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);
}
}
这篇关于FindAll 与 Where 扩展方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!