嵌套与链式联盟

Rei*_*l-- 2 linq performance ienumerable

从逻辑上讲,以下都是相同的:

var foo = (  A.Union(B).Union(C).Union(D)  ).ToList();
var bar = (  A.Union(B.Union(C.Union(D)))  ).ToList();
var baz = (  D.Union(C.Union(B.Union(A)))  ).ToList();
Run Code Online (Sandbox Code Playgroud)

他们应该在最后返回完全相同的列表.


它们之间有什么区别(如果有的话)?

我猜想唯一的区别是与你在每个集合中迭代的频率有关的性能问题?而这foobaz再有完全相同的性能-迭代A4倍,但在D只有一次?

是对的吗?

是否有其他有趣的属性可能会引导您关心做一个而不是另一个?

das*_*ght 5

这些解决方案都没有多次迭代它的参数.此外,参数在他们的文字,这是在给定的顺序重复A,B,C,DfoobarD,C,B,Abaz.

您可以使用一个简单的生成器来演示这一点,该生成器在您迭代时打印它返回的项目:

class VisibleIterator : IEnumerable<string> {
    private readonly string name;
    public VisibleIterator(string name) {
        this.name = name;
    }
    public IEnumerator<string> GetEnumerator() {
        for (var i = 0 ; i != 4 ; i++) {
            var res = name+i;
            Console.WriteLine(res);
            yield return res;
        }
    }
    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }
}
Run Code Online (Sandbox Code Playgroud)

演示.

集合未多次枚举的原因是,UnionIterator<T>后面的代码Union<T>保留了已访问过的项的哈希集:

static IEnumerable<TSource> UnionIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) {
    Set<TSource> set = new Set<TSource>(comparer);
    foreach (TSource element in first)
        if (set.Add(element)) yield return element;
    foreach (TSource element in second)
        if (set.Add(element)) yield return element;
}
Run Code Online (Sandbox Code Playgroud)

Set<TSource> set内部尺寸可能会导致性能差异很小UnionIterator<T>.每个例子中都会有三个这样的集合 - 每个Union呼叫一个.顶级set总是最终得到Union结果的所有成员.set但是,中级可能会有更多项目或更少项目,具体取决于您合并集合的顺序以及每个集合中相对项目的数量.