【发布时间】:2016-12-10 03:53:38
【问题描述】:
假设我有一个包含 N 个元素的列表 (list1)。
然后我有一个 M list2) 中删除的元素的所有索引。
我想以最有效的方式使用list2 索引相应地删除list1 上的元素。
第一种方法是通过 for 循环:
for (int i = 0; i < list2.Count; i++)
list1.RemoveAt(list2[i]);
这项工作非常好(当然,我需要订购 list2),但在最坏的情况下具有 O(M*N) 复杂度(M 次迭代,RemoveAt 为 O(n))
另一种解决方案是创建一个临时列表,用不应删除的元素填充它,然后使用 LINQ intersect 方法
List<T> tempList = new List<T>();
for (int i = 0; i < list1.Count; i++)
if (list2.Contains(i))
tempList.Add(list1[i]);
list1.Intersect(tempList);
虽然起初我对 Intersect 的 O(N+M) 复杂性感到兴奋,但我最终意识到我需要首先进行 N 次迭代来填充 tempList,然后所有优势都消失了(让我们假设list2 是HashSet 在第二种情况下,我不关心排序,而只关心 O(1) Contains)
经过一番挖掘,我仍然无法找到一种方法来执行类似RemoveAll 的方法,该方法将list1 中的所有元素都删除为list2 中存储的值。
有没有机会让它尽可能高性能?
PS:对于那些认为“过早的优化是万恶之源”的人,请考虑我的代码实际上运行良好,但是由于我正在处理一个严格的时间依赖问题,因此每次迭代节省了几个 ns (我将进行大约 150k 次迭代)可以带来显着的改进。
编辑:正如@InBetween 正确指出的那样,在第二个解决方案上使用Intersect 实际上是没有用的,降低它的复杂性会下降。
【问题讨论】:
-
优化是乐趣的根源,恕我直言。早不早!那么我们可以假设
list2已经排序了吗? -
我们可以假设很多关于
list2的事情。我们可以假设它已排序,或者它是HashSet。我可以控制list2以及它是如何创建的,所以我可以对它做很多有趣的事情。但我同意你的看法,优化很酷! -
你为什么要相交?保留新创建的列表。
-
@InBetween 因为起初它是一个例外,而不是一个交叉,然后我忘记了我在做什么,但你是对的(不过,这似乎不是最好的方法对我来说)
-
第一种使用
LinkedList而不是List的方法是O(n),因为删除操作变成了O(1)
标签: c# linq optimization