Conservazione dell’ordine con LINQ

Uso le istruzioni LINQ to Objects su un array ordinato. Quali operazioni non dovrei fare per essere sicuro che l’ordine dell’array non sia cambiato?

Ho esaminato i metodi di System.Linq.Enumerable , scartando quelli che hanno restituito risultati non IEnumerable. Ho controllato le osservazioni di ciascuno per determinare in che modo l’ordine del risultato sarebbe diverso dall’ordine della fonte.

Conserva assolutamente l’ordine. È ansible mappare un elemento sorgente per indice a un elemento risultato

  • AsEnumerable
  • lanciare
  • concat
  • Selezionare
  • ToArray
  • Elencare

Conserva l’ordine. Gli elementi vengono filtrati, ma non riordinati.

  • distinto
  • tranne
  • intersecare
  • OfType
  • Salta
  • SkipWhile
  • Prendere
  • TakeWhile
  • Dove
  • Zip (nuovo in .net 4)

Distrugge l’ordine: non sappiamo in che ordine aspettarsi risultati.

  • ToDictionary
  • ToLookup

Ridefinisce l’ordine in modo esplicito: usa questi per cambiare l’ordine del risultato

  • Ordinato da
  • OrderByDescending
  • Inverso
  • ThenBy
  • ThenByDescending

Ridefinisce l’ordine secondo alcune regole.

  • GroupBy – Gli oggetti IGrouping vengono restituiti in un ordine basato sull’ordine degli elementi in origine che hanno prodotto la prima chiave di ciascun gruppo IG. Gli elementi di un raggruppamento vengono restituiti nell’ordine in cui appaiono in origine.
  • GroupJoin – GroupJoin conserva l’ordine degli elementi di outer e, per ogni elemento di outer, l’ordine degli elementi di matching dall’interno.
  • Unisci: conserva l’ordine degli elementi esterni e, per ciascuno di questi elementi, l’ordine degli elementi corrispondenti interni.
  • SelectMany – per ciascun elemento di origine, viene richiamato il selettore e viene restituita una sequenza di valori.
  • Unione: quando l’object restituito da questo metodo viene enumerato, Union enumera prima e secondo in tale ordine e restituisce ciascun elemento che non è già stato restituito.

Modifica: ho spostato l’ordine Distinto per preservare in base a questa implementazione .

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

Stai parlando di SQL o di array? Per dirla in altro modo, stai usando LINQ to SQL o LINQ to Objects?

Gli operatori LINQ to Objects in realtà non cambiano la loro origine dati originale: creano sequenze effettivamente supportate dall’origine dati. Le sole operazioni che modificano l’ordine sono OrderBy / OrderByDescending / ThenBy / ThenByDescending – e anche allora, quelle sono stabili per gli elementi ugualmente ordinati. Naturalmente, molte operazioni filtreranno alcuni elementi, ma gli elementi restituiti saranno nello stesso ordine.

Se si converte in una struttura dati diversa, ad esempio con ToLookup o ToDictionary, non credo che l’ordine venga conservato a quel punto, ma è comunque un po ‘diverso. (L’ordine dei valori che associano alla stessa chiave è comunque conservato per le ricerche, credo.)

Se stai lavorando su un array, sembra che tu stia usando LINQ-to-Objects, non SQL; Puoi confermare? La maggior parte delle operazioni LINQ non riordina nulla (l’output sarà nello stesso ordine dell’input) – quindi non applicare un altro ordinamento (OrderBy [Descending] / ThenBy [Descending]).

[modifica: come Jon ha messo più chiaramente; LINQ generalmente crea una nuova sequenza, lasciando da solo i dati originali]

Si noti che se si inseriscono i dati in un Dictionary<,> (ToDictionary) i dati verranno scramble, poiché il dizionario non rispetta alcun ordinamento particolare.

Ma le cose più comuni (Select, Where, Skip, Take) dovrebbero andare bene.

Ho trovato un’ottima risposta in una domanda simile che fa riferimento alla documentazione ufficiale. Per citarla:

Per i metodi Enumerable (LINQ to Objects, che si applica a List ), è ansible fare affidamento sull’ordine degli elementi restituiti da Select , Where o GroupBy . Questo non è il caso per cose che sono intrinsecamente non ordinate come ToDictionary o Distinct .

Dalla documentazione Enumerable.GroupBy :

Gli IGrouping vengono restituiti in un ordine in base all’ordine degli elementi in origine che hanno prodotto la prima chiave di ciascun gruppo IGrouping . Gli elementi di un raggruppamento vengono restituiti nell’ordine in cui appaiono in source .

Questo non è necessariamente vero per i metodi di estensione IQueryable (altri provider LINQ).

Fonte: i metodi enumerabili di LINQ mantengono l’ordine degli elementi relativo?

Qualsiasi “gruppo per” o “ordine per” modificherà l’ordine.