2011-02-03 2 views
5

Supposons que j'ai deux (ou plus) IEnumerable<T> avec de nombreux éléments. Chaque IEnumerable a un autre type T. Les listes peuvent être extrêmement longues et ne doivent pas être complètement chargées en mémoire.Comment puis-je parcourir plusieurs IEnumerables simultanément

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

Ce que je veux faire est de parcourir ces listes, et obtenir un élément contenant un int, une chaîne et un DateTime pour chaque étape, jusqu'à la fin de la plus longue ou la plus courte liste a été atteinte. Les deux cas doivent être pris en charge (bool param plus long vs plus court ou plus). Pour chaque élément indisponible dans les listes plus courtes (parce que la fin a déjà été atteinte), je m'attendrais à des valeurs par défaut. Est-il possible de faire cela avec linq en utilisant l'exécution différée? Je connais la solution utilisant IEnumerators directement combinée avec le rendement de rendement. Voir How can I iterate over two IEnumerables simultaneously in .NET 2

+0

Vous êtes à la recherche d'une fonction 'Zip' qui accepte plus de deux paramètres. – Gabe

+0

Ce que vous pouvez facilement faire en utilisant quelque chose comme 'var résultat = s1.Zip (s2.Zip (s3, (a, b) => nouveau {a, b}), (a, b) => nouveau {a = a , b = ba, c = bb}); ' – Mormegil

+0

Que se passe-t-il si s2 est la liste la plus longue et si s1 ne contient que peu d'éléments? –

Répondre

4

Quelque chose comme ça devrait le faire (Avertissement- non testé):

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

Oui, c'est ce que je voulais dire à la fin de ma question. J'espérais qu'il existe une méthode linq performante. –

+0

@matthias - ceci est encore compatible linq, et fonctionne toujours comme les autres opérateurs linq. –

+0

Je sais, que c'est compatible avec Linq. Il retourne simplement un autre IEnumerable. –

Questions connexes