Préserver l’ordre avec LINQ

J’utilise les instructions LINQ to Objects sur un tableau ordonné. Quelles opérations ne dois-je pas faire pour être sûr que l’ordre du tableau n’est pas modifié?

J’ai examiné les méthodes de System.Linq.Enumerable , en ignorant celles qui renvoyaient des résultats non-IEnumerable. J’ai vérifié les remarques de chacun pour déterminer comment l’ordre du résultat différerait de l’ordre de la source.

Conserve la commande absolument. Vous pouvez mapper un élément source par index sur un élément de résultat

  • AsEnumerable
  • Jeter
  • Concat
  • Sélectionner
  • ToArray
  • Lister

Commande de conserves. Les éléments sont filtrés, mais pas réorganisés.

  • Distinct
  • Sauf
  • Couper
  • De type
  • Sauter
  • SkipWhile
  • Prendre
  • TakeWhile
  • Zip (nouveau dans .net 4)

Détruit l’ordre – nous ne soaps pas dans quel ordre s’attendre.

  • ToDictionary
  • Pour rechercher

Redefines Order Explicitly – utilisez-les pour modifier l’ordre du résultat

  • Commandé par
  • OrderByDescending
  • Sens inverse
  • Puis par
  • ThenByDescending

Redéfinit l’ordre selon certaines règles.

  • GroupBy – Les objects de regroupement sont générés dans un ordre basé sur l’ordre des éléments dans la source qui ont généré la première clé de chaque regroupement. Les éléments d’un regroupement sont fournis dans l’ordre dans lequel ils apparaissent dans la source.
  • GroupJoin – GroupJoin conserve l’ordre des éléments de l’extérieur et, pour chaque élément de l’extérieur, l’ordre des éléments correspondants de l’intérieur.
  • Join – conserve l’ordre des éléments de l’extérieur et, pour chacun de ces éléments, l’ordre des éléments correspondants de inside.
  • SelectMany – pour chaque élément de source, le sélecteur est appelé et une séquence de valeurs est renvoyée.
  • Union – Lorsque l’object renvoyé par cette méthode est énuméré, Union énumère le premier et le second dans cet ordre et génère chaque élément qui n’a pas encore été généré.

Edit: J’ai déplacé Distinct à Presing order en fonction de cette implémentation .

private static IEnumerable DistinctIterator (IEnumerable source, IEqualityComparer comparer) { Set set = new Set(comparer); foreach (TSource element in source) if (set.Add(element)) yield return element; } 

Parlez-vous réellement de SQL ou de tableaux? En d’autres termes, utilisez-vous LINQ to SQL ou LINQ to Objects?

Les opérateurs LINQ to Objects ne modifient pas réellement leur source de données d’origine: ils créent des séquences qui sont efficacement sauvegardées par la source de données. Les seules opérations qui modifient le classement sont OrderBy / OrderByDescending / ThenBy / ThenByDescending – et même dans ce cas, elles sont stables pour des éléments de même ordre. Bien entendu, de nombreuses opérations filtreront certains éléments, mais les éléments renvoyés seront dans le même ordre.

Si vous convertissez dans une structure de données différente, par exemple avec ToLookup ou ToDictionary, je ne pense pas que l’ordre soit préservé à ce stade – mais c’est un peu différent de toute façon. (L’ordre de correspondance des valeurs avec la même clé est préservé pour les recherches, je crois.)

Si vous travaillez sur un tableau, il semble que vous utilisiez LINQ-to-Objects, pas SQL; pouvez-vous confirmer? La plupart des opérations LINQ ne réorganisent rien (la sortie sera dans le même ordre que l’entrée) – donc n’appliquez pas un autre sorting (OrderBy [Descending] / ThenBy [Descending]).

[modifier: comme Jon plus clairement LINQ crée généralement une nouvelle séquence, laissant les données d’origine seules]

Notez que le chargement des données dans un Dictionary<,> (ToDictionary) brouillera les données, car le dictionnaire ne respecte aucun ordre de sorting particulier.

Mais les choses les plus courantes (Select, Where, Skip, Take) devraient convenir.

J’ai trouvé une bonne réponse dans une question similaire qui fait référence à la documentation officielle. Pour le citer:

Pour les méthodes Enumerable (LINQ to Objects, qui s’applique à List ), vous pouvez vous fier à l’ordre des éléments renvoyés par Select , Where ou GroupBy . Ce n’est pas le cas pour les choses qui ne sont pas ToDictionary comme ToDictionary ou Distinct .

De la documentation Enumerable.GroupBy :

Les IGrouping sont IGrouping dans un ordre basé sur l’ordre des éléments dans la source qui ont produit la première clé de chaque IGrouping . Les éléments d’un regroupement sont fournis dans l’ordre dans lequel ils apparaissent dans la source .

Cela n’est pas nécessairement vrai pour les méthodes d’extension IQueryable (autres fournisseurs LINQ).

Source: Les méthodes énumérables de LINQ maintiennent-elles l’ordre relatif des éléments?

Tout “group by” ou “order by” changera éventuellement l’ordre.