关于C#:find()与列表的枚举

Find() vs. enumeration on lists

我正在处理一个代码库,其中需要经常搜索列表中的单个元素。

使用谓词和find()是否比手动在列表上进行枚举更快?

例如:

1
2
3
4
string needle ="example";
FooObj result = _list.Find(delegate(FooObj foo) {
    return foo.Name == needle;
});

VS

1
2
3
4
5
6
string needle ="example";
foreach (FooObj foo in _list)
{
    if (foo.Name == needle)
        return foo;
}

虽然它们在功能上是等价的,但在性能上也是等价的吗?


它们在性能上并不等同。find()方法需要为列表中的每个项调用一个方法(在本例中是委托)。方法调用不是免费的,与内联比较相比,它相对昂贵.forEach版本不需要对每个对象进行额外的方法调用。

也就是说,我不会根据性能来选择一个或另一个,直到我实际分析了我的代码并发现这是一个问题。我还没有发现这个场景对于我编写的代码来说都是一个"热门路径"问题,并且我在find和其他类似的方法中经常使用这个模式。


如果搜索列表的速度太慢,那么您可能会比线性搜索做得更好。如果可以保持列表的排序,可以使用二进制搜索在o(lg n)时间内查找元素。

如果您要搜索大量的内容,可以考虑用字典替换该列表,以按名称索引对象。


从技术上讲,委托版本的运行时性能将比其他版本稍差一点,但在大多数情况下,您很难察觉到任何差异。

更重要的是(ihmo)的代码时间性能是能够写您想要的,而不是您想要的。这在可维护性上有很大的不同。

此原始代码:

1
2
3
4
5
6
string needle ="example";
foreach (FooObj foo in _list)
{
    if (foo.Name == needle)        
        return foo;
}

需要任何维护人员阅读代码并理解您在查找特定项目。

本代码

1
2
3
4
5
6
string needle ="example";
return _list.Find(
    delegate(FooObj foo)
    {
        return foo.Name == needle;
    });

清楚地表明你在寻找一个特定的项目-更容易理解。

最后,使用C 3.0中的功能,此代码:

1
2
string needle ="example";
return _list.Find( foo => foo.Name == needle);

执行完全相同的操作,但在一行中,读取和理解速度更快(好吧,一旦理解lambda表达式,无论如何)。

总之,考虑到备选方案的性能几乎相等,请选择一个使代码更易于读取和维护的方案。


"我正在处理一个代码库,其中需要经常搜索列表中的单个元素。"

最好将数据结构更改为字典而不是列表,以获得更好的性能。


针对list.foreach与foreach迭代(foreach与someList.foreach())提出了类似的问题。

在这种情况下,list.foreach要快一点。


正如贾里德指出的那样,两者之间存在差异。

但是,和往常一样,不要担心,除非你知道这是一个瓶颈。如果这是一个瓶颈,那可能是因为列表很大,在这种情况下,你应该考虑使用一个更快的查找-散列表或二叉树,甚至只是对列表进行排序和进行二叉搜索将给你的日志(n)性能带来比调整线性情况更大的影响。