2012-06-11 13 views
7

का उपयोग करके सूचियां मैं निम्नलिखित डेटा है कहोInterleaving कई (अधिक से अधिक 2) अनियमित LINQ

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

interleaved तो मैं परिणाम प्राप्त होता है आइटम के साथ एक फ्लैट सूची वापस जाने के लिए सबसे आसान तरीका क्या होगा:

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

नीचे दिया गया समाधान बहुत सीधी है। जैसा कि यह पता चला है, यह डीटीबी द्वारा प्रस्तावित समाधान के रूप में लगभग दोगुना है।

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(); 
     } 
    } 
} 
संबंधित मुद्दे