从另一个列表中删除项目


206

我试图弄清楚如何遍历要从另一个项目列表中删除的项目的一般列表。

假设我有一个假设的例子

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

我想使用foreach遍历list1并删除List2中也包含的List1中的每个项目。

我不太确定该怎么做,因为foreach不是基于索引的。


1
您要删除List1中的项目吗?
Srinivas Reddy Thatiparthy'4

1
如果您具有list1 = {foo1}和list2 = {foo1,foo1}会发生什么。应该从列表2中删除foo1的所有副本,还是仅删除第一个副本?
Mark Byers 2010年

2
-1-我认为这个问题都是错的,因此我否决了该问题的每个答案,但是看来问题只是可怕地问了。现在,我无法更改它们-道歉。您是否要从中删除list1存在的项目list2,还是要从中删除list2存在的项目list1?在发表评论时,提供的每个答案都将执行后者。
约翰·拉施(John Rasch)2010年

7
@John Rashch,您应该为那些低票而感到高兴。一些答案是相当概念性的,仅说明如何实现OP想要的功能,甚至不涉及问题中提到的列表。
若昂·安杰洛

3
@Mark-你是对的,完全是我的错-这就是为什么我在这里提出评论以解释发生了什么,我正在寻找一个先前的答案,我在投票后已经有一个类似的问题,并且打算离开找到它后发表评论-事实证明这不是最好的过程!
约翰·拉施(John Rasch)2010年

Answers:


358

您可以使用Except

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

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

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

请注意,Except这不会修改任何一个列表-它会使用结果创建一个新列表。


13
次要点,但这会产生IEnumerable<car>,而不是List<car>。您需要致电ToList()以获取列表。此外,我认为应该是GetSomeOtherList().Except(GetTheList()).ToList()
Adam Robinson

9
using System.Linq;如果您以前没有,也将需要它。
yellavon 2015年

1
注意:list1.Except(list2)不会得到与list2.Except(list1)相同的结果。最后一个为我工作。
radbyx

2
使用时请务必小心,Except因为这实际上会执行设置操作,该操作会区分结果列表。因为我使用的是我没想到这种行为List,而不是一个HashSet有关。
logan

4
为什么这是正确的答案?当然,这可能会给您您所需要的内容,但是,“从一个列表中的另一个列表中删除项目”肯定不等同于设置差异操作,并且您不应该通过接受正确的答案来误导人们!!!
user1935724 '16

37

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

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

3
+1,但在IMO中,您应该在该list2.Remove(item);语句周围使用方括号。
2010年

2
@sr pt:我总是在出现在另一行的语句上使用方括号,而不是在我可以/可以将其放置在与流控制语句相同的行上的单语句块上。
亚当·罗宾逊

4
@uriz:忽视的什么是优雅的资格,这是实际上做什么的问题的唯一答案(删除在主列表中的项目); 另一个答案将创建一个列表,如果该列表是从其他呼叫者传入的,则该列表希望对其进行修改而不是获得替换列表,则这可能是不希望的。
亚当·罗宾逊

5
@uriz @AdamRobinson,因为我们正在讨论优雅的解决方案……list1.ForEach(c => list2.Remove(c));
David Sherret 2014年

1
“优雅”应表示“坚持维护此代码的开发人员会发现它简单易懂”,这就是为什么这是最佳答案。
赛斯

22

我建议使用LINQ扩展方法。您可以像这样用一行代码轻松地做到这一点:

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

当然,这是假定要从list2中删除的list1中的对象是同一实例。


2
它也删除重复项。
2016年

17

在我的情况下,我有两个不同的列表,具有相同的标识符,有点像外键。“ 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是
rogue39nin

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));

9
甚至可以使用方法组更简单-integers.RemoveAll(remove.Contains);
瑞安


7

解决方案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();

0

由于Except不修改列表,因此可以在以下位置使用ForEachList<T>

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

这可能不是最有效的方法,但是它很简单,因此易读,并且会更新原始列表(这是我的要求)。


-3

来呀..

    List<string> list = new List<string>() { "1", "2", "3" };
    List<string> remove = new List<string>() { "2" };

    list.ForEach(s =>
        {
            if (remove.Contains(s))
            {
                list.Remove(s);
            }
        });

3
-1。删除第一项后,这将引发异常。另外,遍历列表以删除通常是一个更好的主意,因为它通常较小。您还迫使这样做的更多列表遍历。
亚当·罗宾逊
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.