从一个列表中删除另一个列表中的项目。

289

我正在尝试弄清楚如何遍历一个通用的项目列表,并从另一个项目列表中删除它们。

假设我有以下假想例子:

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
我想用foreach遍历List1,然后移除List2中包含的每个List1中的元素。但是因为foreach不是基于索引的,所以我不太确定如何实现。

1
你想要移除List1中也在List2中存在的项目吗? - Srinivas Reddy Thatiparthy
1
如果你有list1 = { foo1 }和list2 = { foo1, foo1 },那么应该发生什么?是应该从list2中删除所有的foo1副本,还是只删除第一个? - Mark Byers
2
-1 - 我曾经对这个问题中的每个答案进行了负评,因为我认为它们全部都是错误的,但现在看来这个问题本身就很糟糕。现在我无法改变它们,非常抱歉。你想要从list1中删除存在于list2中的项目,还是想要从list2中删除存在于list1中的项目?在本评论编写时,提供的每个答案都将执行后者操作。 - John Rasch
7
@John Rashch,你应该在投反对票时少冲动一些。有些答案相当抽象,仅演示了如何实现OP想要的内容,甚至未涉及问题中提到的列表。 - João Angelo
3
@Mark - 你说得对,完全是我的错 - 这就是为什么我在这里放置评论解释发生了什么,我在投票后同时搜索之前已经回答过类似问题的答案,准备找到它后再留下评论 - 结果证明这不是最好的处理方式! - John Rasch
显示剩余3条评论
11个回答

494

您可以使用Except

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
List<car> result = list2.Except(list1).ToList();

您可能甚至不需要那些临时变量:

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();
请注意,Except 不会修改任何一个列表 - 它会创建一个新的列表并返回结果。

20
小细节,但这将生成一个IEnumerable<car>,而不是List<car>。你需要调用ToList()来获取一个列表。此外,我认为应该是GetSomeOtherList().Except(GetTheList()).ToList() - Adam Robinson
12
如果您之前没有使用过System.Linq,则还需要添加using System.Linq; - yellavon
1
注意:list1.Except(list2)不会给出与list2.Except(list1)相同的结果。最后一个对我起作用了。 - radbyx
6
使用Except时要小心,因为它实际上执行的是集合操作,会使结果列表去重。由于我正在使用的是List而不是HashSet,所以我没有预料到这种行为。[相关链接](https://dev59.com/CHA85IYBdhLWcg3wBO7h) - logan
7
为什么这是正确的答案?在你的情境中,这可能会给你想要的结果,但是,“从一个列表中删除项目”显然不等同于集合差分操作,你不应该误导人们接受这个作为正确答案! - user1935724
显示剩余2条评论

50

你不需要索引,因为List<T>类允许您通过使用Remove函数按值而不是索引来删除项目。

foreach(car item in list1) list2.Remove(item);

5
+1,但我认为你应该在“list2.Remove(item);”语句周围使用括号。 - ANeves
5
我总是在跨行的语句上使用括号,但对于可以/放置在同一行流程控制语句上的单个语句块,我则不使用括号。 - Adam Robinson
2
只要你保持一致,使用括号与否并不重要。在我看来 :) - Ian P
14
不考虑什么是优雅的资格,这是唯一一个真正按照问题要求执行的答案(删除主列表中的项目);另一个答案创建了一个新列表,如果列表是从期望被修改而不是获得替换列表的不同调用方传递过来的,则可能不理想。 - Adam Robinson
11
@uriz @AdamRobinson,既然我们正在讨论优雅的解决方案... list1.ForEach(c => list2.Remove(c)); - David Sherret
显示剩余6条评论

32
在我的情况下,我有两个不同的列表,具有共同的标识符,类似于外键。 "nzrytmn" 引用的第二种解决方案:
var result =  list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();

最适合我的情况。

我需要在不加载已经注册的记录的情况下加载DropDownList。

谢谢!!!

这是我的代码:

t1 = new T1();
t2 = new T2();

List<T1> list1 = t1.getList();
List<T2> list2 = t2.getList();

ddlT3.DataSource= list2.Where(s => !list1.Any(p => p.Id == s.ID)).ToList();
ddlT3.DataTextField = "AnyThing";
ddlT3.DataValueField = "IdAnyThing";
ddlT3.DataBind();

你从未解释过DDlT3是什么。 - c-sharp-and-swiftui-devni

25

我建议使用LINQ扩展方法。您可以轻松地用一行代码完成它,如下所示:

list2 = list2.Except(list1).ToList();

当然前提是list1中要移除的对象与list2中的是同一个实例。


2
它也会去除重复项。 - Incredible

18
list1.RemoveAll(l => list2.Contains(l));

a.k.a. "totally-impure" :-) - Xan-Kun Clark-Davis
1
这有什么问题。使用Except创建另一个列表看起来更好,尤其是当两个列表都非常小的时候。 - Mike Keskinov
2
由于两种列表方法都是O(N),这将导致O(N^2),对于大型列表可能会成为一个问题。 - tigrou

15
你可以使用LINQ,但我会选择使用 RemoveAll 方法。我认为这个方法更能表达你的意图。
var integers = new List<int> { 1, 2, 3, 4, 5 };

var remove = new List<int> { 1, 3, 5 };

integers.RemoveAll(i => remove.Contains(i));

12
使用方法组甚至更简单,您可以执行 - integers.RemoveAll(remove.Contains); - Ryan
这个解决方案比LINQ Except方法更快吗?或者使用更少的资源? - lebarillier

10

解决方案1:您可以这样做:

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();

但在某些情况下,这种解决方案可能无效。如果它无效,您可以使用我的第二个解决方案。

解决方案2:

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();

假设list1是你的主列表,list2是你的次要列表,你想获取list1中不包含list2项目的项。

 var result =  list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();

1

由于Except不会修改列表,因此您可以在List<T>上使用ForEach

list2.ForEach(item => list1.Remove(item));

这可能不是最高效的方法,但它很简单易懂,而且可以更新原始列表(这是我的要求)。


0

我认为将列表A转换为字典,然后对第二个列表进行foreach循环并调用DictA.Remove(item)会更快,否则我认为大多数解决方案都会直接或间接地导致对列表A进行多次迭代。

如果列表很小,那么这可能无关紧要。


0

如果您有两个具有不同数据模型的列表

List<FeedbackQuestionsModel> feedbackQuestionsList = new();

List<EmployeesFeedbacksQuestionsModel> employeeQuestionsList = new();

var resultList = feedbackQuestionsList.Where(p => !employeeQuestionsList.Any(x => x.Question == p.Question)).ToList();
feedbackQuestionsList = resultList.ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接