LINQ并设置差异

Pie*_*aud 20 c# linq ienumerable set-theory

我有两个集合ab.我想计算a或者b两者中的项目集合,而不是两者中的项目集合(逻辑异或).有了LINQ,我可以想出这个:

IEnumerable<T> Delta<T>(IEnumerable<T> a, IEnumerable<T> b)
{
    return a.Except (b).Union (b.Except (a));
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否还有其他更有效或更紧凑的方法来产生两个集合之间的差异.

编辑1:Jon Skeet发布了第一个解决方案,它不依赖于a来保留项目的顺序HashSet.我想知道是否有其他方法可以保持输出的顺序ab输出.

Jon*_*eet 26

HashSet<T>直接使用- 它有一个SymmetricExceptWith方法:

HashSet<T> data = new HashSet<T>(a);
data.SymmetricExceptWith(b);
Run Code Online (Sandbox Code Playgroud)

编辑:如果你想维持订单,这里有一个替代方案:

HashSet<T> data = new HashSet<T>(a);
data.IntersectWith(b);
foreach (T t in a.Concat(b))
{
    if (!data.Contains(t))
    {
        yield return t;
    }
}
Run Code Online (Sandbox Code Playgroud)

这有以下重要区别:

  • 这两个ab被重复两次以上.在某些情况下,这可能是一件非常糟糕的事情 - 您可以调用ToList它们中的每一个来保留缓冲区.
  • 如果有任何重复ab,他们将得到多次.如果你想避免这种情况,你可以保留一组已经产生的值.在这一点上,它将等同于:

    a.Concat(b).Except(a.Intersect(b))
    
    Run Code Online (Sandbox Code Playgroud)

尽管如此,这仍然只是两个设置操作,而不是原始代码中的三个操作.


Cam*_*and 5

给定a.除了(b)和b.除了(a)是不相交的,你可以使用concat代替union,保存集合运算符(并且concat更有效).

return a.Except (b).Concat (b.Except (a));
Run Code Online (Sandbox Code Playgroud)

这仍然会在每个列表中运行两次.