使用LINQ交错多个(超过2个)不规则列表

说我有以下数据

IEnumerable<IEnumerable> items = new IEnumerable[] { new int[] { 1, 2, 3, 4 }, new int[] { 5, 6 }, new int[] { 7, 8, 9 } }; 

返回包含交错项的平面列表的最简单方法是什么,以便得到结果:

1,5,7,2,6,8,3,9,4

注意:运行时不知道内部列表的数量。

您所描述的内容本质上是一种转置方法 ,其中包含悬垂项目并且结果被展平 。 这是我的尝试:

 static IEnumerable> TransposeOverhanging( this IEnumerable> source) { var enumerators = source.Select(e => e.GetEnumerator()).ToArray(); try { T[] g; do { yield return g = enumerators .Where(e => e.MoveNext()).Select(e => e.Current).ToArray(); } while (g.Any()); } finally { Array.ForEach(enumerators, e => e.Dispose()); } } 

例:

 var result = items.TransposeOverhanging().SelectMany(g => g).ToList(); // result == { 1, 5, 7, 2, 6, 8, 3, 9, 4 } 

以下解决方案非常直接。 事实certificate,它的速度几乎是dtb提出的解决方案的两倍。

 private static IEnumerable Interleave(this IEnumerable> source ) { var queues = source.Select(x => new Queue(x)).ToList(); while (queues.Any(x => x.Any())) { foreach (var queue in queues.Where(x => x.Any())) { yield return queue.Dequeue(); } } } 

根据dtb的回答 ,这是我的尝试。 它避免了外部SelectMany和内部ToArray调用。

 public static IEnumerable Interleave(this IEnumerable> source) { var enumerators = source.Select(e => e.GetEnumerator()).ToArray(); try { bool itemsRemaining; do { itemsRemaining = false; foreach (var item in enumerators.Where(e => e.MoveNext()).Select(e => e.Current)) { yield return item; itemsRemaining = true; } } while (itemsRemaining); } finally { Array.ForEach(enumerators, e => e.Dispose()); } } 
  • 处理所有枚举器,即使抛出exception也是如此
  • 急切地评估外部序列,但对内部序列使用惰性评估。

 public static IEnumerable Interleave(IEnumerable> sequences) { var enumerators = new List>(); try { // using foreach here ensures that `enumerators` contains all already obtained enumerators, in case of an expection is thrown here. // this ensures proper disposing in the end foreach(var enumerable in sequences) { enumerators.Add(enumerable.GetEnumerator()); } var queue = new Queue>(enumerators); while (queue.Any()) { var enumerator = queue.Dequeue(); if (enumerator.MoveNext()) { queue.Enqueue(enumerator); yield return enumerator.Current; } } } finally { foreach(var enumerator in enumerators) { enumerator.Dispose(); } } } 

虽然它没有“dtb”的答案那么优雅,但它也有效,它的单线程:)

 Enumerable.Range(0, items.Max(x => x.Count())) .ToList() .ForEach(x => { items .Where(lstChosen => lstChosen.Count()-1 >= x) .Select(lstElm => lstElm.ElementAt(x)) .ToList().ForEach(z => Console.WriteLine(z)); });