Itérer deux listes ou tableaux avec une seule instruction ForEach en C #

Ceci juste pour la connaissance générale:

Si j’ai deux, disons, List , et que je veux parcourir les deux avec la même boucle foreach, pouvons-nous le faire?

modifier

Juste pour clarifier, je voulais faire ceci:

List listA = new List { "ssortingng", "ssortingng" }; List listB = new List { "ssortingng", "ssortingng" }; for(int i = 0; i < listA.Count; i++) listB[i] = listA[i]; 

Mais avec un foreach =)

Ceci est connu comme une opération Zip et sera pris en charge dans .NET 4.

Avec cela, vous pourriez écrire quelque chose comme:

 var numbers = new [] { 1, 2, 3, 4 }; var words = new [] { "one", "two", "three", "four" }; var numbersAndWords = numbers.Zip(words, (n, w) => new { Number = n, Word = w }); foreach(var nw in numbersAndWords) { Console.WriteLine(nw.Number + nw.Word); } 

En alternative au type anonyme avec les champs nommés, vous pouvez également enregistrer des accolades en utilisant un Tuple et son assistant Tuple.Create statique:

 foreach (var nw in numbers.Zip(words, Tuple.Create)) { Console.WriteLine(nw.Item1 + nw.Item2); } 

Si vous ne voulez pas attendre .NET 4.0, vous pouvez implémenter votre propre méthode Zip. Ce qui suit fonctionne avec .NET 2.0. Vous pouvez ajuster l’implémentation en fonction de la manière dont vous souhaitez gérer le cas où les deux énumérations (ou listes) ont des longueurs différentes: celle-ci se poursuit jusqu’à la fin de l’énumération plus longue et renvoie les valeurs par défaut des éléments manquants.

  static IEnumerable> Zip(IEnumerable first, IEnumerable second) { IEnumerator firstEnumerator = first.GetEnumerator(); IEnumerator secondEnumerator = second.GetEnumerator(); while (firstEnumerator.MoveNext()) { if (secondEnumerator.MoveNext()) { yield return new KeyValuePair(firstEnumerator.Current, secondEnumerator.Current); } else { yield return new KeyValuePair(firstEnumerator.Current, default(U)); } } while (secondEnumerator.MoveNext()) { yield return new KeyValuePair(default(T), secondEnumerator.Current); } } static void Test() { IList names = new ssortingng[] { "one", "two", "three" }; IList ids = new int[] { 1, 2, 3, 4 }; foreach (KeyValuePair keyValuePair in ParallelEnumerate(names, ids)) { Console.WriteLine(keyValuePair.Key ?? "" + " - " + keyValuePair.Value.ToSsortingng()); } } 

Vous pouvez utiliser Union ou Concat, le premier supprime les doublons, le dernier ne le fait pas.

 foreach (var item in List1.Union(List1)) { //TODO: Real code goes here } foreach (var item in List1.Concat(List1)) { //TODO: Real code goes here } 

Voici une méthode d’extension IEnumerable <> personnalisée qui peut être utilisée pour parcourir deux listes simultanément.

 using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApplication1 { public static class LinqCombinedSort { public static void Test() { var a = new[] {'a', 'b', 'c', 'd', 'e', 'f'}; var b = new[] {3, 2, 1, 6, 5, 4}; var sorted = from ab in a.Combine(b) orderby ab.Second select ab.First; foreach(char c in sorted) { Console.WriteLine(c); } } public static IEnumerable> Combine(this IEnumerable s1, IEnumerable s2) { using (var e1 = s1.GetEnumerator()) using (var e2 = s2.GetEnumerator()) { while (e1.MoveNext() && e2.MoveNext()) { yield return new Pair(e1.Current, e2.Current); } } } } public class Pair { private readonly TFirst _first; private readonly TSecond _second; private int _hashCode; public Pair(TFirst first, TSecond second) { _first = first; _second = second; } public TFirst First { get { return _first; } } public TSecond Second { get { return _second; } } public override int GetHashCode() { if (_hashCode == 0) { _hashCode = (ReferenceEquals(_first, null) ? 213 : _first.GetHashCode())*37 + (ReferenceEquals(_second, null) ? 213 : _second.GetHashCode()); } return _hashCode; } public override bool Equals(object obj) { var other = obj as Pair; if (other == null) { return false; } return Equals(_first, other._first) && Equals(_second, other._second); } } } 

Vous pouvez aussi simplement utiliser une variable entière locale si les listes ont la même longueur:

 List listA = fillListA(); List listB = fillListB(); var i = 0; foreach(var itemA in listA) { Console.WriteLine(itemA + listB[i++]); } 

Non, vous devrez utiliser une boucle for pour cela.

 for (int i = 0; i < lst1.Count; i++) { //lst1[i]... //lst2[i]... } 

Vous ne pouvez pas faire quelque chose comme

 foreach (var objCurrent1 int lst1, var objCurrent2 in lst2) { //... } 

Si vous voulez un élément avec celui correspondant, vous pouvez le faire

 Enumerable.Range(0, List1.Count).All(x => List1[x] == List2[x]); 

Cela retournera true si chaque article est égal à celui correspondant sur la deuxième liste

Si c’est presque mais pas tout à fait ce que vous voulez, cela vous aiderait si vous en développiez plus.

Cette méthode fonctionnerait pour une implémentation de liste et pourrait être implémentée comme méthode d’extension.

 public void TestMethod() { var first = new List {1, 2, 3, 4, 5}; var second = new List {"One", "Two", "Three", "Four", "Five"}; foreach(var value in this.Zip(first, second, (x, y) => new {Number = x, Text = y})) { Console.WriteLine("{0} - {1}",value.Number, value.Text); } } public IEnumerable Zip(List first, List second, Func selector) { if (first.Count != second.Count) throw new Exception(); for(var i = 0; i < first.Count; i++) { yield return selector.Invoke(first[i], second[i]); } } 

Depuis C # 7, vous pouvez utiliser Tuples …

 int[] nums = { 1, 2, 3, 4 }; ssortingng[] words = { "one", "two", "three", "four" }; foreach (var tuple in nums.Zip(words, (x, y) => (x, y))) { Console.WriteLine($"{tuple.Item1}: {tuple.Item2}"); } // or... foreach (var tuple in nums.Zip(words, (x, y) => (Num: x, Word: y))) { Console.WriteLine($"{tuple.Num}: {tuple.Word}"); } 

Je comprends / j’espère que les listes ont la même longueur: Non, votre seul pari va avec une vieille norme pour la boucle.