我有 2 个列表:list1
和list2
(均为 int 类型)
现在我想删除list2
from的内容list1
。我如何在 C# 中做到这一点?
PS:不要使用循环。
重要变化
正如评论中所指出的,在内部使用了一个集合,因此最终结果中将不存在.Except()
任何重复的成员。list1
产生两个序列的集合差
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except(v=vs.110).aspx
但是,有一个解决方案既 O(N) 又保留原始列表中的重复项:修改RemoveAll(i => list2.Contains(i))
方法以使用 aHashSet<int>
来保存排除集。
List<int> list1 = Enumerable.Range(1, 10000000).ToList();
HashSet<int> exclusionSet = Enumerable.Range(500000, 10).ToHashSet();
list1.Remove(i => exclusionSet.Contains(i));
扩展方法ToHashSet()
在MoreLinq中可用。
原始答案
您可以使用 Linq
list1 = list1.Except(list2).ToList();
更新
出于好奇,我对我的解决方案与@HighCore 的解决方案进行了简单的基准测试。
由于list2
只有一个元素,他的代码更快。随着list2
越来越大,他的代码变得非常慢。看起来他是O(N-squared)(或者更具体地说是 O(list1.length*list2.length),因为其中的每个项目list1
都与 中的每个项目进行比较list2
)。没有足够的数据点来检查我的解决方案的 Big-O,但是当list2
有多个元素时它会快得多。
用于测试的代码:
List<int> list1 = Enumerable.Range(1, 10000000).ToList();
List<int> list2 = Enumerable.Range(500000, 10).ToList(); // Gets MUCH slower as 10 increases to 100 or 1000
Stopwatch sw = Stopwatch.StartNew();
//list1 = list1.Except(list2).ToList();
list1.RemoveAll(i => list2.Contains(i));
sw.Stop();
var ms1 = sw.ElapsedMilliseconds;
更新 2
此解决方案为变量分配一个新列表list1
。正如@Толя 指出的那样,对原始文件的其他引用(如果有的话)list1
将不会被更新。除了最小RemoveAll
尺寸的list2
. 如果没有其他参考必须看到更新,那么最好是出于这个原因。
list1.RemoveAll(x => list2.Contains(x));
你可以使用这个:
List<T> result = list1.Except(list2).ToList();
这将从中删除每个secondList
项目firstList
:
firstList.RemoveAll( item => { secondList.Contains(item); } );