从通用列表中获取对称差集

18

我有两个不同的列表,需要比较这两个列表并获取除了这两个列表之间的交集以外的所有内容。如何实现这个功能(使用C#)?


除了并集以外,一切都是空的。你是不是想说除了交集? - Mehrdad Afshari
你是指“但交集”吗? - Simon Fox
4
在集合论中被称为“对称差集”: http://en.wikipedia.org/wiki/Set_theory - Michael Todd
@Daniel:我想他的意思是指那些不在两个列表中的所有内容。 - fretje
好的 - 联合将包含两个列表中的所有内容。因此,假设您将结果限制为列表中的值,则结果始终为空集。也许您的意思是列表交集中不存在的所有内容?(即一个列表中独有的所有值?) - Aaron
显示剩余2条评论
7个回答

43

如果您的意思是除了交集(即对称差异)之外的所有东西的集合,您可以尝试:

var set = new HashSet<Type>(list1);
set.SymmetricExceptWith(list2);

2
太好了 - 在我看来,那似乎是最好的方法。 - Jon Skeet
2
非常好!这比我之前写的要干净多了。 - Reed Copsey

20
您可以使用Except函数获取两个列表的交集之外的所有元素
var differences = listA.Except(listB).Union(listB.Except(listA));

如果你想获取除了并集之外的所有内容:

var allButUnion = new List<MyClass>();

(并集包含了两个列表中的所有元素 - 除了并集之外,剩下的部分是空集...)


1
既然你在英语中使用“交集”一词来描述它的含义,那么在代码中使用它也是有意义的,不是吗? :) - Jon Skeet
虽然我记得,当我不得不为某些事情做这件事时,这比执行总并集并删除交集要稍微更有效一些... - Reed Copsey
1
listA.Except(listB).Concat(listB.Except(listA)) 可能更高效。 - Djeefther Souza
我从你的例子开始。然后我尝试编写一个通用版本,但有人比我先完成了它: https://www.rosettacode.org/wiki/Symmetric_difference - Colin
这个博客文章中也提到了 SymmetricExceptWith 方法: http://www.skylark-software.com/2011/07/linq-and-set-notation.html - Colin

7
你的意思是只包括一个列表中的所有内容,或者另一个列表中的所有内容吗?那么这样如何:
var allButIntersection = a.Union(b).Except(a.Intersect(b));

那可能会有些低效,但它相当简单地表明了您的意思(当然,假设我正确地理解了您的意思)。


2

这是一个通用的扩展方法。Rosetta Code使用Concat,而Djeefther Souza认为这更有效率。

public static class LINQSetExtensions
{
    // Made aware of the name for this from Swift
    // https://dev59.com/XnI-5IYBdhLWcg3wxbjv
    // Generic implementation adapted from https://www.rosettacode.org/wiki/Symmetric_difference
    public static IEnumerable<T> SymmetricDifference<T>(this IEnumerable<T> first, IEnumerable<T> second)
    {
        // I've used Union in the past, but I suppose Concat works. 
        // No idea if they perform differently. 
        return first.Except(second).Concat(second.Except(first));
    }
}

我实际上没有对此进行基准测试。我认为这取决于Union和Concat是如何实现的。在我的理想世界中,.NET使用不同的算法来处理不同的数据类型或集合大小,但对于IEnumerable,它无法提前确定集合大小。

另外,你可以忽略我的回答- Jon Skeet表示HashSet方法“非常好-这看起来是我做到最好的方式。”


1

像这样吗?

String[] one = new String[] { "Merry", "Metal", "Median", "Medium", "Malfunction", "Mean", "Measure", "Melt", "Merit", "Metaphysical", "Mental", "Menial", "Mend", "Find" };
            String[] two = new String[] { "Merry", "Metal", "Find", "Puncture", "Revise", "Clamp", "Menial" };

List<String> tmp = one.Except(two).ToList();
tmp.AddRange(two.Except(one));

String[] result = tmp.ToArray();

0

使用 Except:

List<int> l1 = new List<int>(new[] { 1, 2, 3, 4 });
List<int> l2 = new List<int>(new[] { 2, 4 });
var l3 = l1.Except(l2);

2
那样做只会返回在l1中而不在l2中的项目吗?如果l2中有l1中没有的项目呢? - Michael Todd

0
var theUnion = list1.Concat(list2);
var theIntersection = list1.Intersect(list2);
var theSymmetricDifference = theUnion.Except(theIntersection);

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