将一个列表中仅有的新项添加到另一个列表中

4

我有两个列表:

List<string> _list1;
List<string> _list2;

我需要在_list1中添加所有不同的_list2项...
我该如何使用LINQ实现这个功能?
谢谢
3个回答

10
你可以使用IEnumerable<T>.Union方法:
var _list1 = new List<string>(new[] { "one", "two", "three", "four" });
var _list2 = new List<string>(new[] { "three", "four", "five" });

_list1 = _list1.Union(_list2);

// _distinctItems now contains one, two, three, four, five

编辑

您也可以使用其他帖子使用的方法:

_list1.AddRange(_list2.Where(i => !_list1.Contains(i));

这两种方法都会增加额外的开销。

第一种方法使用一个新的List来存储Union结果(然后将它们赋值回到_list1)。

第二种方法将创建一个内存中的Where表示,并将其添加到原始List中。

选择你的毒药。在我看来,Union使代码更清晰一些(因此值得额外的开销,至少在你能证明它成为问题之前)。


这将创建一个新列表;它不会添加任何内容到_list1。 - Gabe
@Carlos - 有没有特别的原因不使用这个? - Justin Niessner
在这个特定的例子中,这样做是可以的。但是如果集合有某种状态,例如一些ORM对象的列表,当更新到数据库时可能会失败,因为具有所有与数据库相关信息的集合是在分配新集合时丢失的。 - Carlos Muñoz
@Carlos - 这里描述的两种方法都依赖于Equals。Union和Contains都允许您提供自己的IComparer来代替依赖Equals。不过,你对ORM问题的看法是正确的。如果您正在使用ORM管理的列表(处理插入等操作),那么AddRange将更准确地定义您的意图。 - Justin Niessner
@Justin:是的,我的错,我编辑了我的评论。我已经遇到过合并两个列表时的问题,所以我记得这种情况。 - Carlos Muñoz
1
+1 我喜欢使用 Union 来保持简洁,但我相信 AddRange(list2.Except(..)) 比你的第二种方法更快(请参见 Carlos 回答中的评论)。Union 可能会稍微慢一些,因为它会创建一个新的列表,但在渐近意义下应该是相同的。 - Lasse Espeholt

10
// Add all items from list2 except those already in list1
list1.AddRange(list2.Except(list1));

3
+1 我相信这比卡洛斯的回答更快。 (请参见他回答中的评论) - Lasse Espeholt

5
_list1.AddRange( _list2.Where(x => !_list1.Contains(x) ) );

1
这个程序不会是O(n^2)吧?理想情况下,它不应该比排序更慢,因为排序的时间复杂度是O(n*log(n))。 - Lasse Espeholt
@lasseespeholt 你不能确定这些列表是否已排序。 - Carlos Muñoz
这句话的意思是Union操作的时间复杂度为O(n),比其他操作要快得多。 - Lasse Espeholt
@Carlos - 你可以将第一个列表中的项添加到 HashSet<T> 中,然后测试第二个列表中每个项的成员资格 - 这种方法在较长列表的长度上是线性的。这就是为什么使用 Union 和 Except 更有效率的原因。 - Lee
我也已经点赞了其他解决方案,我认为那是在我的之后出现的,所以我对此没有任何问题。 - Carlos Muñoz
显示剩余3条评论

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