ChatGPT解决这个技术问题 Extra ChatGPT

从另一个列表中删除项目

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

所以假设我有这个作为一个假设的例子

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

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

我不太确定如何去做,因为 foreach 不是基于索引的。

您想删除 List1 中同时也在 List2 中的项目吗?
如果你有 list1 = { foo1 } 和 list2 = { foo1, foo1 } 会发生什么。应该从 list2 中删除 foo1 的所有副本,还是只删除第一个?
-1 - 我对这个问题的每个答案都投了反对票,因为我认为他们都错了,但看起来这个问题只是被问得很糟糕。现在,我无法改变它们——抱歉。您要从 list1 中删除 list2 中存在的项目,还是要从 list2 中删除 list1 中存在的项目?在发表此评论时,提供的每个答案都将执行后者。
@John Rashch,您应该对那些反对票不那么高兴。一些答案是相当概念性的,仅演示如何实现 OP 想要的,甚至与问题中提到的列表无关。
@Mark - 你是对的,完全是我的错 - 这就是为什么我把评论放在这里解释发生了什么,我正在寻找以前的答案,我在投票后已经遇到过类似的问题,并且打算离开在我找到它之后发表评论 - 事实证明这不是最好的过程!

M
Mark Byers

您可以使用 Except

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

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

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

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


次要问题,但这将产生 IEnumerable<car>,而不是 List<car>。您需要调用 ToList() 来获取列表。另外,我认为应该是GetSomeOtherList().Except(GetTheList()).ToList()
如果您以前没有 using System.Linq;,您还需要它。
注意:list1.Except(list2) 不会给出与 list2.Except(list1) 相同的结果。最后一个对我有用。
使用 Except 时要小心,因为它实际上执行了一个 set 操作,它区分了结果列表。我没有预料到这种行为,因为我使用的是 List,而不是 HashSetRelated.
为什么这是正确答案?当然,这可能会在您的上下文中为您提供所需的内容,但是,“从另一个列表中删除项目”当然不等同于设置差异操作,您不应该通过接受这个作为正确答案来误导人们!!!!
A
Adam Robinson

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

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

+1,但 IMO 您应该在 list2.Remove(item); 语句周围使用方括号。
@sr pt:我总是在出现在另一行的语句上使用括号,而不是在我可以/确实与流控制语句放在同一行的单语句块上。
只要您保持一致,是否使用括号都没关系.. IMO :)
@uriz:不管什么是优雅的条件,这是唯一真正做到问题所说的答案(删除主列表中的项目);另一个答案会创建一个新列表,如果该列表是从另一个期望修改它而不是获取替换列表的调用者传入的,则这可能是不可取的。
@uriz @AdamRobinson,因为我们正在讨论优雅的解决方案... list1.ForEach(c => list2.Remove(c));
G
Gabriel Santos Reis

在我的例子中,我有两个不同的列表,有一个共同的标识符,有点像外键。 “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 是什么
B
Berkshire

我建议使用 LINQ extension methods。您可以使用一行代码轻松完成,如下所示:

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

这当然是假设您从 list2 中删除的 list1 中的对象是同一个实例。


它也会删除重复项。
A
Alexandre Castro
list1.RemoveAll(l => list2.Contains(l));

又名“完全不纯” :-)
它有什么问题。它看起来比使用除外创建另一个列表更好。特别是当两个列表都非常小时。
由于两个列表方法都是 O(N),这将导致 O(N^2),这可能是大型列表的问题。
J
João Angelo

您可以使用 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));

或者更简单的方法组你可以做 - integers.RemoveAll(remove.Contains);
此解决方案是否比 LINQ 除外方法更快?还是使用更少的资源?
n
nzrytmn

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

N
Necriis

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

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

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


L
Luke Briner

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

如果列表很小,则可能无关紧要。


I
Ian P

给你吧。。

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

-1。这将在删除第一项后引发异常。此外,(通常)遍历要删除的列表是一个更好的主意,因为它通常更小。您还强迫更多的列表遍历以这种方式进行。