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




array object (9)

Ceci juste pour la connaissance générale:

Si j'en ai deux, disons List , et que je veux répéter les deux avec la même boucle foreach, pouvons-nous faire cela?

modifier

Juste pour clarifier, 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 =)


Answers

Depuis C # 7, vous pouvez utiliser Tuples ...

int[] nums = { 1, 2, 3, 4 };
string[] 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}");
}

Si vous voulez un élément avec le correspondant que vous pourriez faire

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

Cela retournera vrai si chaque élément 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 élaboriez plus.


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)
{
    //...
}

Vous pouvez également simplement utiliser une variable d'entier local si les listes ont la même longueur:

List<classA> listA = fillListA();
List<classB> listB = fillListB();

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

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

Avec cela, vous seriez capable d'é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);
}

Comme une alternative au type anonyme avec les champs nommés, vous pouvez également enregistrer sur accolades en utilisant un Tuple et son aide statique Tuple.Create:

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

Je comprends / espère que les listes ont la même longueur: Non, votre seul pari va avec un vieux standard pour la boucle.


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

}

Les deux options que j'utilise sont:

list1.AddRange(list2);

ou

list1.Concat(list2);

Cependant, j'ai remarqué que comme je l'ai utilisé lors de l'utilisation de la méthode AddRange avec une fonction récursive, qui s'appelle très souvent, j'ai obtenu une exception SystemOutOfMemoryException, car le nombre maximal de dimensions a été atteint.

(Message Google traduit)
Les dimensions du tableau ont dépassé la plage prise en charge.

L'utilisation de Concat résolu ce problème.




c#  

c#