从列表中删除子列表
我有2个列表: list1
和list2
(都是int类型)
现在我想从list1
删除list2
内容。 我怎么能在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))
方法以使用HashSet
来保存排除集。
List list1 = Enumerable.Range(1, 10000000).ToList(); HashSet exclusionSet = Enumerable.Range(500000, 10).ToHashSet(); list1.Remove(i => exclusionSet.Contains(i));
ToHashSet()
中提供了扩展方法ToHashSet()
。
原始答案
你可以使用Linq
list1 = list1.Except(list2).ToList();
UPDATE
出于好奇,我对我的解决方案与@ HighCore进行了简单的基准测试。
对于只有一个元素的list2
,他的代码更快。 随着list2
变得越来越大,他的代码变得非常慢。 它看起来像是O(N平方) (或更具体地是O(list1.length * list2.length),因为list1
中的每个项目都与list2
每个项目进行比较)。 没有足够的数据点来检查我的解决方案的Big-O,但是当list2
具有多个元素时,它会快得多。
用于测试的代码:
List list1 = Enumerable.Range(1, 10000000).ToList(); List 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
其他引用(如果有的话)将不会更新。 除了最小尺寸的list2
这个解决方案的性能远远超过RemoveAll
。 如果没有其他引用必须看到更新,那么最好是因为这个原因。
list1.RemoveAll(x => list2.Contains(x));
你可以用这个:
List result = list1.Except(list2).ToList();
这将从secondList
删除secondList
中的每个项目:
firstList.RemoveAll( item => { secondList.Contains(item); } );