在C#中比较多个重叠数据集的最有效方法是什么?

时间:2015-03-19 08:53:54

标签: c# performance

我想知道在C#中使用不同数量的记录在多个集合中查找重叠数据的最有效方法是什么?

让我们举个例子:

Set1: +- 20 records       Set2: +- 50 records
 ID | Value                ID | Value
 1  | Value01               1 | ValueA
 2  | Value02               2 | ValueB
 3  | Value03               3 | Value01
 4  | Value04               4 | ValueD
 5  | Value05               5 | Value17
   ...                           ....
20  | Value20              50 | Value XY


Set3: +- 2 000 records    Set4: +- 3 000 records
 ID | Value               ID | Value
 1  | Random               1 | Dog
 2  | Random02             2 | Duck
 3  | Random03             3 | John
 4  | Random04             4 | Pen
 5  | Ranodm05             5 | Argument
   ...                           ....

想法是chceck,每个集合只包含独占记录。如果一个记录存在于多个表中,则该记录应标记为重叠。

数学上说:

∀A,B,C,D:A∩(B∪C D)= {}∧B∩(C D)= {}∧C∩D= {}

我想要实现的是在C#中创建一个函数,该函数将输入4组并且可能返回类似字典的内容。包含3个词典(set1重叠,set2重叠,set3重叠)

因此输出应该如下所示:

var result = new Dictionary<SetsEnum, Dictionary<int, Dictionary<SetsEnum, int>>>
{
  { SetsEnum.Set1, 
    { 
      {<set1overlappingRowId1>,
        {
          { SetsEnum.<setX>, <overlappingRowIdX> },
          { SetsEnum.<setY>, <overlappingRowIdY> } 
        }
      },
      {<set1overlappingRowId2>,
        {
          { SetsEnum.<setZ>, <overlappingRowIdZ> }
        }
      }
    }
  }
}

我希望我在括号中没有犯任何错误。 基本上它应该说是这样的:

Set1-Row5与:Set2-Row42,Set3-Row1513重叠 Set1-Row18与:Set4-Row481重叠 Set2-Row30与:Set3-Row987重叠 等

我希望它足够清楚。

只有接近我才能想到id:

  1. 按大小从最小到最大的顺序设置
  2. 对于第1组中的每个记录,检查第2,3和4组中的重叠。
  3. 对于第2组中的每条记录,检查第3组和第4组中的重叠。
  4. 对于第3组中的每条记录,检查第4组中的重叠。
  5. 返回重叠字典。
  6. 在C#中存在这样的简单解决方案吗?

    聚苯乙烯。在fack中,我想知道另外一个解决方案。如果发现任何重叠,请使用标记标记此记录,然后仅使用不重叠的记录(这可能会加快速度。但实现此类功能似乎不必要复杂)

2 个答案:

答案 0 :(得分:0)

由于您正在进行某种内部联接,因此可以在此处使用此作为起点 - 请注意,它会生成完整的外部联接:

public static IEnumerable<TResult> GenerateMapping<TLeft, TRight, TResult>(IEnumerable<TLeft> leftList,
                                                                                IEnumerable<TRight> rightList,
                                                                                Func<TLeft, String> leftSortKey,
                                                                                Func<TRight, String> rightSortKey,
                                                                                Func<TLeft, TRight, TResult> factory)
        where TLeft : class
        where TRight : class
    {
        var result = new List<TResult>();
        var sortedLeftList = leftList.OrderBy(leftSortKey, StringComparer.OrdinalIgnoreCase).ToArray();
        var sortedRightList = rightList.OrderBy(rightSortKey, StringComparer.OrdinalIgnoreCase).ToArray();

        var left = 0;
        var right = 0;
        var total = sortedLeftList.Length + sortedRightList.Length;

        while (left + right < total)
        {
            if (left < sortedLeftList.Length && right < sortedRightList.Length)
            {
                var compare = String.Compare(
                    leftSortKey(sortedLeftList[left]),
                    rightSortKey(sortedRightList[right]),
                    StringComparison.OrdinalIgnoreCase);

                if (compare < 0)
                {
                    result.Add(factory(sortedLeftList[left], null));
                    left++;
                }
                if (compare > 0)
                {
                    result.Add(factory(null, sortedRightList[right]));
                    right++;
                }
                if (compare == 0)
                {
                    result.Add(factory(sortedLeftList[left], sortedRightList[right]));
                    left++;
                    right++;
                }
            }
            else if (left < sortedLeftList.Length)
            {
                result.Add(factory(sortedLeftList[left], null));
                left++;
            }
            else if (right < sortedRightList.Length)
            {
                result.Add(factory(null, sortedRightList[right]));
                right++;
            }
        }

        return result;
    }

可能一些使用Lookups的实现会更快地执行。 您可以通过搜索[inner | left | right | full] join和LinQ

找到它们

答案 1 :(得分:0)

如果将所有集合连接到一个集合,然后按值排序或按值排序,则可以轻松计算每个值出现的次数。您需要跟踪每个项目来自哪个集合 在这个例子中,我使用了3个小集合和简单的整数和字符串,但这个想法应该是清楚的。

struct MyData
{
    public int SetID { get; set; }
    public int ID { get; set; }
    public string Value { get; set; }

    public override string ToString()
    {
        return string.Format("SetID={0}, ID={1}, Value={2}", SetID, ID, Value);
    }
}

然后搜索本身:

var set1 = new Dictionary<int, string>();
var set2 = new Dictionary<int, string>();
var set3 = new Dictionary<int, string>();

set1.Add(1, "Value01");
set1.Add(2, "Value02");
set1.Add(3, "Value03");
set1.Add(4, "Value04");
set1.Add(5, "Value05");
set1.Add(6, "Value06");
set1.Add(7, "Value07");
set1.Add(8, "Value08");
set1.Add(9, "Value09");
set1.Add(10, "Value10");

set2.Add(1, "ValueA");
set2.Add(2, "ValueB");
set2.Add(3, "Value01");
set2.Add(4, "ValueD");
set2.Add(5, "Value17");
set2.Add(6, "ValueX");
set2.Add(7, "ValueY");
set2.Add(8, "ValueZ");
set2.Add(9, "Value16");

set3.Add(1, "ValueT");
set3.Add(2, "Random");
set3.Add(3, "Duck");
set3.Add(4, "Arg");
set3.Add(5, "Value03");
set3.Add(6, "Value01");
set3.Add(7, "ValueD");
set3.Add(8, "ValueB");
set3.Add(9, "Whatever");

var search = set1.Select(kvp => new MyData { SetID = 1, ID = kvp.Key, Value = kvp.Value })
    .Concat(set2.Select(kvp => new MyData { SetID = 2, ID = kvp.Key, Value = kvp.Value })
).Concat(set3.Select(kvp => new MyData { SetID = 3, ID = kvp.Key, Value = kvp.Value })
).GroupBy(md => md.Value);

var unique = new HashSet<MyData>();
var dupes = new HashSet<MyData>();
foreach (var grp in search) {
    if (grp.Take(2).Count() > 1) {
        foreach (var data in grp) dupes.Add(data);
    } else {
        unique.Add(grp.Single());
    }
}
foreach (var data in unique) Console.WriteLine(data);
Console.WriteLine();
foreach (var data in dupes) Console.WriteLine(data);

dupes将包含:

SetID=1, ID=1, Value=Value01
SetID=2, ID=3, Value=Value01
SetID=3, ID=6, Value=Value01
SetID=1, ID=3, Value=Value03
SetID=3, ID=5, Value=Value03
SetID=2, ID=2, Value=ValueB
SetID=3, ID=8, Value=ValueB
SetID=2, ID=4, Value=ValueD
SetID=3, ID=7, Value=ValueD