Domanda

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?

È stato utile?

Soluzione

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 differirebbe dall'ordine della fonte.

Conserva assolutamente l'ordine. Puoi mappare un elemento sorgente per indice su un elemento risultato

  • AsEnumerable
  • Cast
  • Concat
  • Seleziona
  • ToArray
  • ToList

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

  • Distinto
  • Ad eccezione
  • Intersect
  • OfType
  • Vai
  • SkipWhile
  • Date
  • TakeWhile
  • Dove
  • Zip (nuovo in .net 4)

Distrugge l'ordine: non sappiamo in quale ordine aspettarsi i risultati.

  • ToDictionary
  • ToLookup

Ridefinisce l'ordine in modo esplicito: utilizzali per modificare l'ordine del risultato

  • OrderBy
  • OrderByDescending
  • Reverse
  • ThenBy
  • ThenByDescending

Ridefinisce l'ordine in base ad alcune regole.

  • GroupBy: gli oggetti IGrouping vengono generati in un ordine basato sull'ordine degli elementi nell'origine che ha prodotto la prima chiave di ciascun IGrouping. Gli elementi in un raggruppamento sono prodotti nell'ordine in cui appaiono nella fonte.
  • GroupJoin - GroupJoin conserva l'ordine degli elementi dell'esterno e, per ogni elemento dell'esterno, l'ordine degli elementi corrispondenti dall'interno.
  • Unisci: conserva l'ordine degli elementi di esterno e, per ciascuno di questi elementi, l'ordine degli elementi di corrispondenza di interno.
  • SelectMany: per ciascun elemento di origine viene richiamato il selettore e viene restituita una sequenza di valori.
  • Union: quando viene elencato l'oggetto restituito con questo metodo, Union enumera il primo e il secondo in quell'ordine e produce ogni elemento che non è già stato ceduto.

Modifica: ho spostato Distinct in Preserving order in base a questo implementazione .

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

Altri suggerimenti

In realtà 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 l'origine dati originale, ma creano sequenze che sono effettivamente supportate dall'origine dati. Le uniche operazioni che modificano l'ordinamento sono OrderBy / OrderByDescending / ThenBy / ThenByDescending - e anche in questo caso, sono stabili per gli elementi equamente ordinati. Naturalmente, molte operazioni filtreranno alcuni elementi, ma gli elementi che verranno restituiti saranno nello stesso ordine.

Se si converte in una diversa struttura di dati, ad es. con ToLookup o ToDictionary, non credo che l'ordine sia conservato a quel punto, ma è comunque un po 'diverso. (Credo che l'ordine dei valori associati alla stessa chiave sia preservato per le ricerche.)

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 soli i dati originali]

Nota che spingendo i dati in un Dictionary<,> (ToDictionary) si mescoleranno i dati, poiché il dizionario non rispetta alcun particolare ordinamento.

Ma le cose più comuni (Seleziona, Dove, Salta, Prendi) dovrebbero andare bene.

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

Per i metodi Enumerable (LINQ to Objects, che si applica a List<T>), puoi fare affidamento sull'ordine degli elementi restituiti da Select, Where o GroupBy. Questo non è il caso di cose intrinsecamente non ordinate come ToDictionary o Distinct.

  

Dalla Enumerable.GroupBy :

     

Gli IGrouping<TKey, TElement> oggetti vengono prodotti in un ordine basato sull'ordine degli elementi nell'origine che ha prodotto la prima chiave di ogni source. Gli elementi in un raggruppamento vengono generati nell'ordine in cui appaiono in IQueryable.

Questo non è necessariamente vero per <=> metodi di estensione (altri provider LINQ).

Fonte: I metodi enumerabili di LINQ mantengono l'ordine relativo degli elementi?

Qualsiasi 'raggruppa per' o 'ordina per' cambierà probabilmente l'ordine.

La domanda qui si riferisce specificamente a LINQ-to-Objects.

Se usi LINQ-to-SQL invece non c'è ordine lì a meno che tu non lo imponga con qualcosa del tipo:

mysqlresult.OrderBy(e=>e.SomeColumn)

Se non si esegue questa operazione con LINQ-to-SQL, l'ordine dei risultati può variare tra le query successive, anche degli stessi dati, che potrebbero causare un bug intermittente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top