关于如何从一个列表中排除另一个列表的项目,我有一个相当具体的问题。常见的方法,如Except()不会这样做,原因如下:
因为我自己创建了一个解决方案,所以我不会要求解决方案。然而,在多次执行此方法之后 - “ANTS性能分析器”显示该方法经过了整个执行时间的75%(40个中的30秒)。问题是:是否有更快的方法来执行相同的操作?我试图优化我当前的代码,但它仍然缺乏性能。这是:
private void removedoubles(List<int> exclude, List<int> listcopy)
{
for (int j = 0; j < exclude.Count(); j++)
{
for (int i = 0; i < listcopy.Count(); i++)
{
if (listcopy[i] == exclude[j])
{
if (i % 2 == 0) // even
{
//listcopy.RemoveRange(i, i + 1);
listcopy.RemoveAt(i);
listcopy.RemoveAt(i);
i = i - 1;
}
else //odd
{
//listcopy.RemoveRange(i - 1, i);
listcopy.RemoveAt(i - 1);
listcopy.RemoveAt(i - 1);
i = i - 2;
}
}
}
}
}
其中:
我认为LINQ可能会有所帮助,但我不太了解它的语法。
答案 0 :(得分:5)
更快的方式(O(n)
)将执行以下操作:
exclude
列表并将其转换为HashSet
(O(n)
)O(n)
),因为HashSet
中的状态测试是O(1)
。也许您甚至可以更改算法,以便exclude
集合从一开始就是HashSet
,这样您就可以省略步骤1并获得更快的速度。
(您目前的方式是O(n^2)
。)
编辑:
另一个想法如下:您可能正在创建一些列表的副本并使此方法修改它? (根据参数名称猜测。)然后,您可以将其更改为以下内容:将原始数组传递给方法,并使方法分配新数组并返回它(您的方法签名应该比private List<int> getWithoutDoubles(HashSet<int> exclude, List<int> original)
)更像。
编辑:
如果您按以下方式重新组织输入数据,它可能会更快:由于项目总是成对删除(甚至索引+以下奇数索引),您应该提前配对它们!如果整数你的列表成为整数对的列表。这样你的方法可能是这样的:
private List<Tuple<int, int>> getWithoutDoubles(
HashSet<int> exclude, List<Tuple<int, int>> original)
{
return original.Where(xy => (!exclude.Contains(xy.Item1) &&
!exclude.Contains(xy.Item2)))
.ToList();
}
(删除第一个或第二个项目在排除集合中的对)。也许您可以将项目打包到自定义类型中,而不是Tuple
。
答案 1 :(得分:2)
撤消循环,使其从.Count - 1
开始,然后转到0,这样您就不必在其中一个案例中更改i
,Count
仅评估一次每个系列。
答案 2 :(得分:2)
这是另一种获得结果的方法。
var a = new List<int> {1, 2, 3, 4, 5};
var b = new List<int> {1, 2, 3};
var c = (from i in a let found = b.Any(j => j == i) where !found select i).ToList();
c将包含4,5
答案 3 :(得分:1)
您可以将List转换为LinkedList并尝试一下吗? List.RemoveAt()比LinkedList.Remove()更昂贵。