【发布时间】:2015-09-02 11:08:06
【问题描述】:
以下代码:
List<Interval> intervals = new List<Interval>();
List<int> points = new List<int>();
//Initialization of the two lists
// [...]
foreach (var point in points)
{
intervals.RemoveAll (x => x.Intersects (point));
}
当列表大小约为 10000 时,至少比这快 100 倍:
List<Interval> intervals = new List<Interval>();
List<int> points = new List<int>();
//Initialization of the two lists
// [...]
foreach (var point in points)
{
for (int i = 0; i < intervals.Count;)
{
if (intervals[i].Intersects(point))
{
intervals.Remove(intervals[i]);
}
else
{
i++;
}
}
}
这怎么可能? “RemoveAll”在幕后执行了什么?根据MSDN,“RemoveAll”执行线性搜索,因此在 O(n) 中。所以我希望两者的性能相似。
当用“RemoveAt”替换“Remove”时,迭代速度要快得多,与“RemoveAll”相当。但是 both "Remove" 和 "RemoveAt" 都有 O(n) 复杂度,为什么它们之间的性能差异如此之大呢?难道仅仅是因为“Remove (item)”将列表元素与“item”进行比较,而“RemoveAt”没有进行任何比较?
【问题讨论】:
-
RemoveAll不使用 LINQ,它是List<T>上的标准方法。这是由RemoveAll修改集合就地这一事实注意到的——LINQ 不修改集合。 -
@Brainless,你可以加快第二个代码示例,如果使用
intervals.RemoveAt(i);而不是intervals.Remove (intervals[i]);,我想。 -
RemoveAll和Remove都是O(n),所以很容易相信有一个额外的for循环的执行速度会慢n倍。 -
@Brainless RemoveAt 不执行任何比较,它只是删除指定位置的项目。另一方面,删除必须搜索与其参数相等的项目。
-
@Brainless: imo 最好的方法(在可读性和性能方面)是
RemoveAll和 LINQ 的组合:intervals.RemoveAll(i => points.Any(p => i.Intersects(p)));
标签: c# performance linq