2013-09-22 31 views
1

我想合并具有公共元素的数组。我有数组列表如下:合并具有公共元素的数组

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 
}; 

怎么办呢?

+0

在你的情况下,您如何我们合并的事情,如果'3'处处定义?一个数组? –

+1

合并背后的逻辑是什么? –

+0

@SimonBelanger:是的,如果所有数组中都有'3',那么将会合并成一个数组 – user2804123

回答

1

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

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

您可以遍历每个数组,并在其第一个元素和每个找到的元素之后调用Union。一旦完成了列表中的所有数组,您将能够通过再次遍历所有数字来检索单个集合,并对它们调用Find(item)。编号为Find的产品应该放在同一个数组中。

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

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(); 
相关问题