2016-11-16 133 views
0

我有一个项目列表,我想遍历它们的一个子集。现在,我想知道在从列表中删除不需要的项目之间是否存在性能影响差异,然后通过它循环;或者只是在for循环中过滤列表。.RemoveAll和.Where之间的性能差异在C#中

这里是一个例子。

的removeall过的做法:

list.RemoveAll(o => !someOtherList.Contains(o.Property)); 

foreach (var i in list) 
{ 
} 

在哪里做法:

foreach (var i in list.Where(o => someOtherList.Contains(o.Property)) 
{ 
} 

据我所知,第一种方法实际上是要处理的是在列表,作为第二个则不会。这并不是真的关心我。我更关心的是第二种方法中的过滤器是否应用于每次迭代,或者C#是否足够聪明以创建子集并且仅循环该子集(几乎就像使用临时变量的第一种方法)。

+0

如果您的问题归结为“someOtherList.Contains'会被调用多少次?”,我强烈怀疑这两个示例的答案是相同的。 –

+2

哪一个更快?运行两次1000次并计算平均值! – user3185569

+0

@Damien_The_Unbeliever:我的问题归结为多少次list.Where将被调用。 – Johannes

回答

5

我更关注是否适用于每个迭代还是C#是足够聪明的创建通过该子集(几乎像第一 方法有 子集,仅环在第二种方法过滤 一个临时变量)

Linq的Where使用yield为了一次返回一个元素一次请求。

因此,实际上什么是在第二种方法做的是:

1迭代通过列表

2-检查当前的元素相匹配的条件(遍历someOtherList,除非它是一个特殊的查找数据结构如。HashSet

3-一旦我们找到的第一个元素返回它

4-执行的foreach体逻辑

5继续从那里我们停在第3步

含义搜索,如果你决定基于在foreach块内部的一些条件打破,那么也许不是所有的列表可以在该点进行扫描,其在某些情况下,可能会在大型列表上提升性能。

+0

谢谢,这很好地解释了它。 – Johannes

1

作为对其他人已经说过的内容的补充,如果循环操作与您所展示的一样,使用原始性能不会有可忽略的差异。

但是,第一个需要具有物化列表,而后者需要IEnumerable。另外,为了循环内容的运行,首先需要首先实现,直到那时循环内容没有开始完成。使用NOP循环的IOW可能需要大约10秒才能完成某个列表和另一个列表。当循环中有一些工作(可能),那么第一个在进入循环之前花费10秒,那么你需要循环处理的时间。后者OTOH将直接针对找到的每个元素进行循环。如果循环内容是一个耗时的操作,而且可以做到异步,那么后者将是一个明显的赢家。