2011-02-03 5 views
5

Предположим, у меня есть два (или более) IEnumerable<T> со многими элементами. Каждый IEnumerable имеет другой тип T. Списки могут быть чрезвычайно длинными и не должны быть полностью загружены в память.Как я могу перебирать несколько IEnumerables одновременно

IEnumerable<int> ints = getManyInts(); 
IEnumerable<string> strings = getSomeStrings(); 
IEnumerable<DateTime> dates = getSomeDates(); 

То, что я хочу сделать, это перебрать эти списки, и получить элемент, содержащий один INT, одну строку и один DateTime для каждого шага, до конца самого длинного или самый короткий список был достигнут. Оба случая должны поддерживаться (bool param самый длинный или самый короткий или около того). Для каждого элемента, недоступного в более коротких списках (поскольку конец уже достигнут), я бы ожидал значения по умолчанию.

for(Tuple<int,string,DateTime> item in 
    Foo.Combine<int,string,DateTime>(ints, strings, dates)) 
{ 
    int i=item.Item1; 
    string s=item.Item2; 
    DateTime d=item.Item3; 
} 

Можно ли это сделать с помощью linq с использованием отложенного исполнения? Я знаю решение, использующее IEnumerators, в сочетании с возвратом доходности. См How can I iterate over two IEnumerables simultaneously in .NET 2

+0

Вы ищете 'функцию Zip', которая принимает более двух параметров. – Gabe

+0

Что вы можете легко сделать, используя что-то вроде 'var result = s1.Zip (s2.Zip (s3, (a, b) => new {a, b}), (a, b) => new {a = a , b = ba, c = bb}); ' – Mormegil

+0

Что делать, если s2 был самым длинным списком, а s1 состоял из нескольких элементов? –

ответ

4

Что-то, как это должно сделать это (Предупреждение- непроверенные):

public static IEnumerable<Tuple<T, U, V>> IterateAll<T, U, V>(IEnumerable<T> seq1, IEnumerable<U> seq2, IEnumerable<V> seq3) 
{ 
    bool ContinueFlag = true; 
    using (var e1 = seq1.GetEnumerator()) 
    using (var e2 = seq2.GetEnumerator()) 
    using (var e3 = seq3.GetEnumerator()) 
    { 
     do 
     { 
      bool c1 = e1.MoveNext(); 
      bool c2 = e2.MoveNext(); 
      bool c3 = e3.MoveNext(); 
      ContinueFlag = c1 || c2 || c3; 

      if (ContinueFlag) 
       yield return new Tuple<T, U, V>(c1 ? e1.Current : default(T), c2 ? e2.Current : default(U), c3 ? e3.Current : default(V)); 
     } while (ContinueFlag); 
    } 
} 
+0

Да, это то, что я имел в виду в конце моего вопроса. Я надеялся, что есть метод linq. –

+0

@matthias - это все еще linq-совместимый и по-прежнему работает как другие linq-операторы. –

+0

Я знаю, что это совместимо с Linq. Он просто «возвращает» другой IEnumerable. –

Смежные вопросы