更好的Linq版比较扩展版

时间:2013-10-11 14:14:30

标签: performance linq

我需要获得两个IEnumerable之间的差异。我为它写了扩展方法。但正如你所看到的,它有性能损失。任何人都可以写出更好的版本吗?

修改

在第一次回复后,我明白我无法解释清楚。我正在三次访问两个阵列。这是性能损失。它必须是一次性的。

PS:两者都是可选的:)

public static class LinqExtensions
{
 public static ComparisonResult<T> Compare<T>(this IEnumerable<T> source, IEnumerable<T> target)
    {
        // Looping three times is performance penalty!  
        var res = new ComparisonResult<T>
        {
            OnlySource = source.Except(target), 
            OnlyTarget = target.Except(source), 
            Both = source.Intersect(target)
        };
        return res;
    }
}

public class ComparisonResult<T>
{
    public IEnumerable<T> OnlySource { get; set; }
    public IEnumerable<T> OnlyTarget { get; set; }
    public IEnumerable<T> Both { get; set; }
}

2 个答案:

答案 0 :(得分:0)

根据用例,这可能更有效:

 public static ComparisonResult<T> Compare<T>(this IEnumerable<T> source, IEnumerable<T> target)
    {
        var both = source.Intersect(target).ToArray();
        if (both.Any())
        {
            return new ComparisonResult<T>
            {
                OnlySource = source.Except(both),
                OnlyTarget = target.Except(both),
                Both = both
            };
        }
        else
        {
            return new ComparisonResult<T>
            {
                OnlySource = source,
                OnlyTarget = target,
                Both = both
            };
        }
    }

答案 1 :(得分:0)

您正在寻找一种高效的全外连接。

将所有项目插入Dictionary<TKey, Tuple<TLeft, TRight>>。如果给定的密钥不存在,请将其添加到字典中。如果存在,请更新该值。如果设置了“左侧成员”,则表示该项目存在于左侧源集合中(您将其称为source)。正确的成员则相反。你可以在两个集合上使用一次传递来做到这一点。

之后,您遍历此字典的所有值并将相应的项输出到三个集合中的一个,或者您只需将其作为IEnumerable<Tuple<TLeft, TRight>>返回,这样可以节省对结果集合的需求。