将数组与公共元素合并

时间:2013-09-22 13:16:34

标签: c# .net

我想将数组与common元素合并。我有这样的数组列表:

List<int[]> arrList = new List<int[]>
{
    new int[] { 1, 2 },
    new int[] { 3, 4, 5 },
    new int[] { 2, 7 },
    new int[] { 8, 9 },
    new int[] { 10, 11, 12 },
    new int[] { 3, 9, 13 }
};

我想合并这些数组:

List<int[]> arrList2 = new List<int[]>
{
    new int[] { 1, 2, 7 },
    new int[] { 10, 11, 12 },
    new int[] { 3, 4, 5, 8, 9, 13 } //order of elements doesn't matter
};

怎么做?

3 个答案:

答案 0 :(得分:4)

让每个数字成为标记图形中的顶点。对于每个数组,连接给定数组中的数字所指向的顶点。例如。给定数组(1,5,3)创建两个边(1,5)和(5,3)。然后找到图表中的所有连接组件(请参阅:http://en.wikipedia.org/wiki/Connected_component_(graph_theory)

答案 1 :(得分:1)

使用Disjoint-Set Forest data structure。数据结构支持三种操作:

  • MakeSet(item - 创建一个包含单个项目的新集
  • Find(item) - 给定一个项目,查找一个集合。
  • Union(item1, item2) - 给定两个项目,将它们所属的集合连接在一起。

您可以浏览每个数组,并在其第一个元素和您之后找到的每个元素上调用Union。完成列表中的所有数组后,您将能够通过再次遍历所有数字并在其上调用Find(item)来检索各个集合。生成相同集合的Find的数字应该放在同一个数组中。

此方法在O(α(n))摊销中完成合并(α增长非常缓慢,因此出于所有实际目的,它可以被视为一个小常数。)

答案 2 :(得分:1)

我非常确定它不是最好和最快的解决方案,但有效。

static List<List<int>> Merge(List<List<int>> source)
{
    var merged = 0;
    do
    {
        merged = 0;
        var results = new List<List<int>>();
        foreach (var l in source)
        {
            var i = results.FirstOrDefault(x => x.Intersect(l).Any());
            if (i != null)
            {
                i.AddRange(l);
                merged++;
            }
            else
            {
                results.Add(l.ToList());
            }
        }

        source = results.Select(x => x.Distinct().ToList()).ToList();
    }
    while (merged > 0);

    return source;
}

我使用List<List<int>>代替List<int[]>来获取AddRange方法。

用法:

var results = Merge(arrList.Select(x => x.ToList()).ToList());

// to get List<int[]> instead of List<List<int>>
var array = results.Select(x => x.ToArray()).ToList();