179 votes

Itérer les deux Listes ou des Tableaux avec un ForEach déclaration en C#

Juste pour les connaissances générales:

Si j'en ai deux, disons, de la Liste, et je tiens à itérer les deux avec la même boucle foreach, pouvons-nous le faire?

Modifier

Juste pour préciser, je voulais faire ceci:

List<String> listA = new List<string> { "string", "string" };
List<String> listB = new List<string> { "string", "string" };

for(int i = 0; i < listA.Count; i++)
    listB[i] = listA[i];

Mais avec un foreach =)

332voto

Mark Seemann Points 102767

Ceci est connu comme un Zip opération et seront pris en charge .NET 4.

Avec cela, vous pouvez é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);
}

17voto

Joe Points 60749

Si vous ne voulez pas attendre .NET 4.0, vous pouvez implémenter votre propre Zip méthode. Les œuvres suivantes .NET 2.0. Vous pouvez ajuster la mise en œuvre en fonction de la façon dont vous souhaitez gérer le cas où les deux énumérations (ou des listes) ont des longueurs différentes: celui-ci se poursuit jusqu'à la fin de la plus longue énumération, en retournant les valeurs par défaut pour les éléments manquants de la plus courte énumération.

    static IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> first, IEnumerable<U> second)
    {
        IEnumerator<T> firstEnumerator = first.GetEnumerator();
        IEnumerator<U> secondEnumerator = second.GetEnumerator();

        while (firstEnumerator.MoveNext())
        {
            if (secondEnumerator.MoveNext())
            {
                yield return new KeyValuePair<T, U>(firstEnumerator.Current, secondEnumerator.Current);
            }
            else
            {
                yield return new KeyValuePair<T, U>(firstEnumerator.Current, default(U));
            }
        }
        while (secondEnumerator.MoveNext())
        {
            yield return new KeyValuePair<T, U>(default(T), secondEnumerator.Current);
        }
    }

    static void Test()
    {
        IList<string> names = new string[] { "one", "two", "three" };
        IList<int> ids = new int[] { 1, 2, 3, 4 };

        foreach (KeyValuePair<string, int> keyValuePair in ParallelEnumerate(names, ids))
        {
            Console.WriteLine(keyValuePair.Key ?? "<null>" + " - " + keyValuePair.Value.ToString());
        }
    }

13voto

albertein Points 10821

Vous pouvez utiliser de l'Union ou Concat, l'ancien supprime les doublons, le plus tard n'a 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
}

3voto

Samuel Neff Points 35554

Voici une coutume IEnumerable<> méthode d'extension qui peut être utilisé pour faire une boucle par le biais de 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<Pair<TFirst, TSecond>> Combine<TFirst, TSecond>(this IEnumerable<TFirst> s1, IEnumerable<TSecond> s2)
		{
			using (var e1 = s1.GetEnumerator())
			using (var e2 = s2.GetEnumerator())
			{
				while (e1.MoveNext() && e2.MoveNext())
				{
					yield return new Pair<TFirst, TSecond>(e1.Current, e2.Current);
				}
			}

		}


	}
	public class Pair<TFirst, TSecond>
	{
		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<TFirst, TSecond>;
			if (other == null)
			{
				return false;
			}
			return Equals(_first, other._first) && Equals(_second, other._second);
		}
	}

}

-3voto

Benjamin Podszun Points 5120

Je comprends l'espoir que les listes ont la même longueur: Non, votre seul pari va avec un simple vieux standard pour la boucle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X