合并多个列表,每个列表具有可变长度的“弹出”元素

我想将多个列表(可变数量的列表)排序到单个列表中,但保留特定的顺序。 例如:

List A: { 1,2,3,4,5 } List B: { 6,7,8 } List C: { 9,10,11,12 } Result List: { 1,6,9,2,7,10,3,8,11,4,12,5 } 

我得到的唯一想法是从每个列表中删除第一个元素并将其放入结果集中(并重复直到所有列表都为空),但也许有一种更好的方法,不需要创建每个列表的副本,并且没有也不会影响原始列表?

为了更灵活的使用

  public static string MergeArrays(params IList[] items) { var result = new List(); for (var i = 0; i < items.Max(x => x.Count); i++) result.AddRange(from rowList in items where rowList.Count > i select rowList[i]); return string.Join(",", result); } 

  var a = new List() { 1, 2, 3, 4, 5 }; var b = new List() { 6, 7, 8 }; var c = new List() { 9, 10, 11, 12, 0, 2, 1 }; var r = MergeArrays(a, b, c); 

我建议使用IEnumerator枚举列表,同时它们有项目:

 private static IEnumerable Merge(params IEnumerable[] sources) { List> enums = sources .Select(source => source.GetEnumerator()) .ToList(); try { while (enums.Any()) { for (int i = 0; i < enums.Count;) if (enums[i].MoveNext()) { yield return enums[i].Current; i += 1; } else { // exhausted, let's remove enumerator enums[i].Dispose(); enums.RemoveAt(i); } } } finally { foreach (var en in enums) en.Dispose(); } } 

测试

 List A = new List() { 1, 2, 3, 4, 5 }; List B = new List() { 6, 7, 8 }; List C = new List() { 9, 10, 11, 12 }; var result = Merge(A, B, C) .ToList(); Console.Write(string.Join(", ", result)); 

结果是

 1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5 

在我看来,为什么不使用简单的for循环来完成你需要的东西,这没有任何意义呢?

 List list1 = new List { 1, 2, 3, 4, 5 }; List list2 = new List { 6, 7, 8 }; List list3 = new List { 9, 10, 11, 12 }; List resultList = new List(); for (int i = 0; i < list1.Count || i < list2.Count || i < list3.Count; i++) { if (i < list1.Count) resultList.Add(list1[i]); if (i < list2.Count) resultList.Add(list2[i]); if (i < list3.Count) resultList.Add(list3[i]); } 

结果:1,6,9,2,7,10,3,8,11,4,12,5

这是一个相当简单的方法。 无论如何写起来很有趣。
不,它不是最好的,但它可以工作,你可以扩展它,以满足你很容易使用List>

 //Using arrays for simplicity, you get the idea. int[] A = { 1, 2, 3, 4, 5 }; int[] B = { 6, 7, 8 }; int[] C = { 9, 10, 11, 12 }; List ResultSet = new List(); //Determine this somehow. I'm doing this for simplicity. int longest = 5; for (int i = 0; i < longest; i++) { if (i < A.Length) ResultSet.Add(A[i]); if (i < B.Length) ResultSet.Add(B[i]); if (i < C.Length) ResultSet.Add(C[i]); } //ResultSet contains: { 1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5 } 

正如您所看到的,只需将其弹出到方法中并遍历列表列表,正确确定所有列表的最大长度。

我跟着:

 static void Main(string[] args) { var a = new List() { 1, 2, 3, 4, 5 }; var b = new List() { 6, 7, 8 }; var c = new List() { 9, 10, 11, 12 }; var abc = XYZ(new[] { a, b, c }).ToList(); } static IEnumerable XYZ(IEnumerable> lists) { if (lists == null) throw new ArgumentNullException(); var finished = false; for (int index = 0; !finished; index++) { finished = true; foreach (var list in lists) if (list.Count > index) // list != null (prior checking for count) { finished = false; yield return list[index]; } } } 

我不得不使用IList来拥有索引器和Count 。 它不会创建任何东西(没有枚举器,没有列表等),纯粹的yield return

对于您的问题,我创建了静态方法,可以根据需要合并任何集合:

 public static class CollectionsHandling { ///  /// Merge collections to one by index ///  /// Type of collection elements /// Merging Collections /// New collection {firsts items, second items...} public static IEnumerable Merge(params IEnumerable[] collections) { // Max length of sent collections var maxLength = 0; // Enumerators of all collections var enumerators = new List>(); foreach (var item in collections) { maxLength = Math.Max(item.Count(), maxLength); if(collections.Any()) enumerators.Add(item.GetEnumerator()); } // Set enumerators to first item enumerators.ForEach(e => e.MoveNext()); var result = new List(); for (int i = 0; i < maxLength; i++) { // Add elements to result collection enumerators.ForEach(e => result.Add(e.Current)); // Remobve enumerators, in which no longer have elements enumerators = enumerators.Where(e => e.MoveNext()).ToList(); } return result; } } 

使用示例:

 static void Main(string[] args) { var a = new List { 1, 2, 3, 4, 5 }; var b = new List { 6, 7, 8 }; var c = new List { 9, 10, 11, 12 }; var result= CollectionsHandling.Merge(a, b, c); } 

当您了解它的工作原理时,就可以减少更小的方法。

最短也可能是最慢的解决方案

 int[] A = { 1, 2, 3, 4, 5 }; int[] B = { 6, 7, 8 }; int[] C = { 9, 10, 11, 12 }; var arrs = new[] { A, B, C }; var merged = Enumerable.Range(0, arrs.Max(a => a.Length)) .Select(x => arrs.Where(a=>a.Length>x).Select(a=>a[x])) .SelectMany(x=>x) .ToArray(); 

UPD。

另一种解决方法 – 我只是重构了@Sinatr的答案。

 static IEnumerable XYZ(IEnumerable> lists) { if (lists == null) throw new ArgumentNullException(); var index = 0; while (lists.Any(l => l.Count > index)) { foreach (var list in lists) if (list.Count > index) yield return list[index]; index++; } }