如何在C#中有效地从另一个中减去一个巨大的列表

时间:2011-02-23 14:04:49

标签: c# performance collections

我有一个非常长的Ids(整数)列表,它代表了我数据库中当前的所有项目:

var idList = GetAllIds();

我还有另一个巨大的通用列表,其中包含要添加到数据库的项目:

List<T> itemsToAdd;

现在,我想删除ID已经在idList中的通用列表中的所有项目。 目前idList是一个简单的数组,我按这样减去列表:

itemsToAdd.RemoveAll(e => idList.Contains(e.Id));

我很确定它可以快得多,所以我应该为两个集合使用什么数据类型以及减去它们的最有效做法是什么?

谢谢!

4 个答案:

答案 0 :(得分:23)

LINQ可以提供帮助:

itemsToAdd.Except(idList)

您的代码很慢,因为List<T>.ContainsO(n)。因此,您的总费用为O(itemsToAdd.Count*idList.Count)

您可以将idList设为HashSet<T> O(1) .Contains。或者只使用为您执行此操作的Linq .Except扩展方法。

请注意,.Except也会从左侧删除所有重复项。即新int[]{1,1,2}.Except(new int[]{2})将导致{1},第二个1将被移除。但我认为你的情况没问题,因为ID通常是唯一的。

答案 1 :(得分:18)

暂时将idList转换为HashSet<T>并使用相同的方法,即:

items.RemoveAll(e => idListHash.Contains(e.Id));

它应该快得多

答案 2 :(得分:5)

假设以下前提是正确的:

  • idListitemsToAdd可能不包含重复值
  • 您正在使用.NET Framework 4.0

您可以这样使用HashSet<T>

var itemsToAddSet = new HashSet(itemsToAdd);
itemsToAddSet.ExceptWith(idList);

根据文档,ISet<T>.ExceptWith方法非常有效:

  

此方法是O(n)操作,   其中n是元素的数量   其他参数。

在您的情况下,nidList中的项目数。

答案 3 :(得分:2)

你应该使用两个HashSet<int> 请注意,它们是唯一且无序的。