1

我有两个不同类型的集合,TSource分别TTarget是。

TTarget集合将使用在集合中找到的项目进行更新,TSource但由于这些更改包括工作流触发器,我必须知道添加、更新和删除的内容。

Func<TSource, TTarget, bool> Equals假设一个函数,在这些集合上运行差异的最快方法是什么?此相等函数通常会比较两个对象之间的一个关键字段,但并非总是如此。

我能找到的唯一解决方案是明确说明它们的关键是什么(即不要将其隐藏在内部Equals()并使用Intersectand HashSet

void Main()
{
    string[] target = new[] { "1", "2", "3", "4" }; // collection that will be updated
    int[] source = new[] { 0, 1, 2 }; // collection with the items for comparison and update

    // I've used simple types to reduce complexity

    Func<string, string> targetKeyFunc = t => t;
    Func<int, string> sourceKeyFunc = s => s.ToString();

    HashSet<string> keySet = new HashSet<string>(
        source.Select(sourceKeyFunc).Intersect(target.Select(targetKeyFunc)));

    foreach(var it in source)
        if(keySet.Contains(sourceKeyFunc(it)))
            Console.WriteLine("Updated: {0}", it);
        else
            Console.WriteLine("Added: {0}", it);

    foreach(var it in target)
        if(!keySet.Contains(targetKeyFunc(it)))
            Console.WriteLine("Removed: {0}", it);
}

这是一个很好的实现,但将我绑定到使用键选择器。是否有更快或尽可能快的替代方案允许使用Equals()如上所述的函数?

4

1 回答 1

0

如果您只有一个Func<TSource, TTarget, bool> Equals函数,则唯一可能的算法是有两个嵌套循环并将每个元素与其他元素进行比较。性能是二次方的,很快就无法接受。

对密钥的了解将可能的“比较函数”限制为按键相等的直观概念。这允许使用散列。

因此,您需要基于 aFunc<TItem, TKey>并使用某种散列(HashSetToDictionaryToLookup

用数据库术语来说,您想要的是完全外连接。我建议您保留一个Dictionary<TKey, Tuple<List<TItem>, List<TItem>>包含给定密钥的两个来源的项目集。首先,您将来自两个来源的所有项目添加到字典中,然后迭代其值并查看哪些键仅包含来自其中一个来源的项目。

于 2013-07-14T16:30:09.083 回答