在两个不同类型的集合上运行差异更新的最快方法

本文关键字:运行 更新 方法 集合 两个 同类型 | 更新日期: 2023-09-27 18:22:12

我有两个不同类型的集合,分别是TSourceTTarget

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

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

我能找到的唯一解决方案是明确他们的密钥是什么(即不要将其隐藏在Equals()中并使用IntersectHashSet:

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()函数?

在两个不同类型的集合上运行差异更新的最快方法

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

对键的了解将可能的"比较器函数"的类型限制为键相等的直观概念。这使得可以使用哈希。

因此,您需要基于Func<TItem, TKey>并使用某种哈希(HashSetToDictionaryToLookup)。

在数据库术语中,您想要的是一个完整的外部联接。我建议您保留一个Dictionary<TKey, Tuple<List<TItem>, List<TItem>>,它包含给定密钥的两个来源的项集。首先,将两个源中的所有项添加到字典中,然后对其值进行迭代,查看哪些键只有其中一个源的项。