9

我有 2 个列表:list1list2(均为 int 类型)

现在我想删除list2from的内容list1。我如何在 C# 中做到这一点?

PS:不要使用循环。

4

4 回答 4

24

重要变化

正如评论中所指出的,在内部使用了一个集合,因此最终结果中将不存在.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. 如果没有其他参考必须看到更新,那么最好是出于这个原因。

于 2013-01-17T21:57:34.260 回答
9
list1.RemoveAll(x => list2.Contains(x));
于 2013-01-17T21:58:08.193 回答
5

你可以使用这个:

List<T> result = list1.Except(list2).ToList();
于 2013-01-17T21:57:34.637 回答
1

这将从中删除每个secondList项目firstList

firstList.RemoveAll( item => { secondList.Contains(item); } );
于 2013-01-17T22:15:34.003 回答