web-dev-qa-db-fra.com

Dans quel ordre un C # pour chaque boucle parcourt-il une liste <T>?

Je me demandais dans quel ordre une boucle foreach en C # boucle à travers un objet System.Collections.Generic.List<T>.

J'ai trouvé ne autre question sur le même sujet, mais je ne pense pas que cela réponde à ma question à ma satisfaction.

Quelqu'un déclare qu'aucun ordre n'est défini. Mais comme quelqu'un d'autre le déclare, l'ordre dans lequel il traverse un tableau est fixe (de 0 à Longueur-1). 8.8.4 L'instruction foreach

Il a également été dit que la même chose vaut pour toutes les classes standard avec une commande (par exemple List<T>). Je ne trouve aucune documentation à l'appui. Donc pour tout ce que je sais, cela pourrait fonctionner comme ça maintenant, mais peut-être que dans la prochaine version .NET, ce sera différent (même si cela est peu probable).

J'ai également regardé la documentation List(t).Enumerator sans chance.

ne autre question connexe indique que pour Java, il est spécifiquement mentionné dans la documentation:

List.iterator() renvoie un itérateur sur les éléments de cette liste dans l'ordre approprié. "

Je cherche quelque chose comme ça dans la documentation C #.

Merci d'avance.

Edit: Merci à vous tous pour toutes vos réponses (incroyable la rapidité avec laquelle j'ai eu tant de réponses). Ce que je comprends de toutes les réponses, c'est que List<T> Itère toujours dans l'ordre de son indexation. Mais je voudrais toujours voir une paix claire de la documentation le mentionnant, semblable à la documentation Java sur List .

75
Matthijs Wessels

Sur page Source de référence Microsoft pour List<T> Enumérateur, il est explicitement indiqué que l'itération se fait de 0 à Longueur-1:

internal Enumerator(List<T> list) {
    this.list = list;
    index = 0;
    version = list._version;
    current = default(T);
}

public bool MoveNext() {

    List<T> localList = list;

    if (version == localList._version && ((uint)index < (uint)localList._size)) 
    {                                                     
        current = localList._items[index];                    
        index++;
        return true;
    }
    return MoveNextRare();
}

J'espère que c'est toujours pertinent pour quelqu'un

2
apokrovskyi

Fondamentalement, cela dépend de l'implémentation de IEnumerator - mais pour un List<T> il ira toujours dans l'ordre naturel de la liste, c'est-à-dire le même ordre que l'indexeur: list[0], list[1], list[2] etc.

Je ne crois pas que ce soit explicitement documenté - du moins, je n'ai pas trouvé une telle documentation - mais je pense que vous pouvez le traiter comme garanti. Toute modification de cet ordre romprait inutilement toutes sortes de codes. En fait, je serais surpris de voir une implémentation de IList<T> qui a désobéi à cela. Certes, il serait agréable de le voir spécifiquement documenté ...

94
Jon Skeet

Dans votre lien, la réponse acceptée indique C # Language Specification Version 3.0, page 24 :

L'ordre dans lequel foreach parcourt les éléments d'un tableau est le suivant: Pour les tableaux unidimensionnels, les éléments sont parcourus dans un ordre d'index croissant, en commençant par l'index 0 et se terminant par l'index Longueur - 1. Pour les tableaux multidimensionnels, les éléments sont traversés de sorte que les indices de la dimension la plus à droite soient augmentés en premier, puis la dimension gauche suivante, et ainsi de suite à gauche. L'exemple suivant imprime chaque valeur dans un tableau à deux dimensions, dans l'ordre des éléments:

using System;
class Test
{
  static void Main() {
      double[,] values = {
          {1.2, 2.3, 3.4, 4.5},
          {5.6, 6.7, 7.8, 8.9}
      };
      foreach (double elementValue in values)
          Console.Write("{0} ", elementValue);
      Console.WriteLine();
  }
}

La production produite est la suivante: 1,2 2,3 3,4 4,5 5,6 6,7 7,8 8,9 Dans l'exemple

int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
the type of n is inferred to be int, the element type of numbers.
8
RvdK

L'ordre est défini par l'itérateur utilisé pour parcourir une collection de données à l'aide d'une boucle foreach.

Si vous utilisez une collection standard indexable (telle qu'une liste), elle traversera la collection en commençant par l'index 0 et en remontant.

Si vous devez contrôler l'ordre, vous pouvez soit contrôler la manière dont l'itération de la collection est gérée par implémenter votre propre IEnumerable , soit vous pouvez trier la liste comme vous le souhaitez avant d'exécuter la boucle foreach.

Cela explique comment Enumerator fonctionne pour la liste générique. Au début, l'élément actuel n'est pas défini et utilise MoveNext pour passer à l'élément suivant.

Si vous lisez MoveNext cela indique qu'il commencera par le premier élément de la collection et de là se déplacera au suivant jusqu'à ce qu'il atteigne la fin de la collection.

4
Brendan Enrick

Les listes semblent renvoyer les articles dans un ordre dans lequel ils se trouvent dans le magasin de sauvegarde - donc s'ils sont ajoutés à la liste de cette façon, ils seront retournés de cette façon.

Si votre programme dépend de la commande, vous voudrez peut-être le trier avant de parcourir la liste.

C'est un peu idiot pour les recherches linéaires - mais si vous avez besoin de l'ordre d'une certaine manière, votre meilleur pari est de faire les articles dans cet ordre.

1
Broam

Je viens de devoir faire quelque chose de similaire comme un hack rapide de code, même si cela n'a pas fonctionné pour ce que j'essayais de faire, il a réorganisé la liste pour moi.

Utilisation de LINQ pour modifier l'ordre

         DataGridViewColumn[] gridColumns = new DataGridViewColumn[dataGridView1.Columns.Count];
         dataGridView1.Columns.CopyTo(gridColumns, 0); //This created a list of columns

         gridColumns = (from n in gridColumns
                        orderby n.DisplayIndex descending
                        select n).ToArray(); //This then changed the order based on the displayindex
1
KillJoy