从列表中删除子列表

Arr*_*rry 6 .net c#

我有2个列表:list1list2(都是int类型)

现在我想删除的内容list2list1.我怎么能在C#中做到这一点?

PS:不要使用循环.

Eri*_* J. 20

重要的变化

正如评论中指出的那样,在.Except()内部使用一个集合,因此list1在最终结果中将缺少任何重复的成员.

产生两个序列的集合差异

http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except(v=vs.110).aspx

但是,有一个解决方案既是O(N)又保留了原始列表中的重复项:修改RemoveAll(i => list2.Contains(i))方法以使用a HashSet<int>来保存排除集.

List<int> list1 = Enumerable.Range(1, 10000000).ToList();
HashSet<int> exclusionSet = Enumerable.Range(500000, 10).ToHashSet(); 

list1.Remove(i => exclusionSet.Contains(i));
Run Code Online (Sandbox Code Playgroud)

MoreLinq中ToHashSet()提供了扩展方法.

原始答案

你可以使用Linq

list1 = list1.Except(list2).ToList();
Run Code Online (Sandbox Code Playgroud)

UPDATE

出于好奇,我对@ HighCore的解决方案进行了简单的基准测试.

因为list2只有一个元素,他的代码更快.随着list2越来越大,他的代码变得极其缓慢.它看起来像是O(N平方)(或者更具体地是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;
Run Code Online (Sandbox Code Playgroud)

更新2

此解决方案为变量分配新列表list1.正如@Толя指出的那样,原始的其他引用(如果有的话)list1将不会更新.RemoveAll除了最小尺寸之外,这个解决方案的性能都非常出色list2.如果没有其他引用必须看到更新,那么最好是因为这个原因.

  • 这实际上并没有从 list1 中删除任何内容。 (2认同)

Fed*_*gui 8

list1.RemoveAll(x => list2.Contains(x));
Run Code Online (Sandbox Code Playgroud)

  • +1因为这实际上从原始列表中删除了项目.(那表示它会从`list1`中删除`list2`中所有元素的所有出现,即使它们重复.) (2认同)
  • @EricJ。`.Except()` 在内部使用了 `Set`,因此移除等操作是 O(n) (2认同)

Tom*_*zzo 5

你可以使用这个:

List<T> result = list1.Except(list2).ToList();
Run Code Online (Sandbox Code Playgroud)