2012-06-11 56 views
7

不規則的名單說我有以下數據交織多個(2個以上)使用LINQ

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

什麼是返回與交錯,所以我得到的結果項的平面列表的最簡單的方法:

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

注:內列出的數量不會在運行時是已知的。

回答

10

你所描述的實質上是一個Transpose Method其中包含懸垂項目,結果爲flattened。這裏是我的嘗試:

static IEnumerable<IEnumerable<T>> TransposeOverhanging<T>(
    this IEnumerable<IEnumerable<T>> 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 } 
+0

愛你的解決方案。認爲這是神奇的線 var enumerators = source.Select(e => e.GetEnumerator())。ToArray(); +1 – Anand

+0

工作了一段時間,並在我的工具欄中添加了新的擴展方法。謝謝! –

-1

雖然它並不像優雅的 「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)); 
            }); 
1

這是我的嘗試,基於dtb's answer。它避免了外部調用SelectMany和內部ToArray

public static IEnumerable<T> Interleave<T>(this IEnumerable<IEnumerable<T>> 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()); 
    } 
} 
2

下面的解決方案非常簡單。事實證明,它的速度也幾乎是dtb提出的解決方案的兩倍。

private static IEnumerable<T> Interleave<T>(this IEnumerable<IEnumerable<T>> source) 
{ 
    var queues = source.Select(x => new Queue<T>(x)).ToList(); 
    while (queues.Any(x => x.Any())) { 
     foreach (var queue in queues.Where(x => x.Any())) { 
      yield return queue.Dequeue(); 
     } 
    } 
} 
0
  • 處理完畢所有統計員,即使引發異常
  • 評估外序列熱切,但使用惰性計算用於內的序列。

public static IEnumerable<T> Interleave<T>(IEnumerable<IEnumerable<T>> sequences) 
{ 
    var enumerators = new List<IEnumerator<T>>(); 
    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<IEnumerator<T>>(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(); 
     } 
    } 
}