2011-02-03 42 views
5

Supongamos que tengo dos (o más) IEnumerable<T> con muchos elementos. Cada IEnumerable tiene otro tipo T. Las listas pueden ser extremadamente largas y no deben cargarse completamente en la memoria.¿Cómo puedo iterar sobre varios IEnumerables simultáneamente?

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

Lo que quiero hacer es iterar sobre estas listas, y obtener un artículo que contiene una intercepción, una cuerda y un DateTime para cada paso, hasta el final de la más larga o la lista más corta se ha alcanzado. Ambos casos deben ser compatibles (bool param más largo vs. más corto o más). Para cada elemento que no está disponible en las listas más cortas (porque el final ya se ha alcanzado) esperaría valores predeterminados.

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; 
} 

¿Es posible hacer esto con linq utilizando la ejecución diferida? Conozco la solución que usa IEnumerators directamente combinada con el retorno de rendimiento. Ver How can I iterate over two IEnumerables simultaneously in .NET 2

+0

Usted está buscando una función 'Zip' que acepte más de dos parámetros. – Gabe

+0

Que puede hacer fácilmente usando algo como 'var result = s1.Zip (s2.Zip (s3, (a, b) => nuevo {a, b}), (a, b) => nuevo {a = a , b = ba, c = bb}); ' – Mormegil

+0

¿Y si s2 fuera la lista más larga y s1 solo tuviera pocos elementos? –

Respuesta

4

Algo así debe hacerlo (ADVERTENCIA- no probado):

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

Sí, eso es lo que quise decir al final de mi pregunta. Esperé que haya un método de ejecución de linq. –

+0

@matthias: todavía es compatible con linq, y funciona igual que otros operadores linq. –

+0

Sé que esto es compatible con Linq. Simplemente 'devuelve' otro IEnumerable. –

Cuestiones relacionadas