it-swarm.com.de

Ordnung erhalten mit LINQ

Ich verwende LINQ to Objects-Anweisungen für ein geordnetes Array. Welche Operationen sollte ich nicht ausführen, um sicherzustellen, dass die Reihenfolge des Arrays nicht geändert wird?

341
Matthieu Durut

Ich untersuchte die Methoden von System.Linq.Enumerable und verwarf alle, die nicht IEnumerable-Ergebnisse zurückgaben. Ich habe die jeweiligen Anmerkungen überprüft, um festzustellen, inwiefern die Reihenfolge des Ergebnisses von der Reihenfolge der Quelle abweicht.

Ordnung absolut erhalten. Sie können ein Quellelement über einen Index einem Ergebniselement zuordnen

  • AsEnumerable
  • Besetzung
  • Concat
  • Wählen
  • ToArray
  • Auflisten

Ordnung bewahren. Elemente werden gefiltert, aber nicht neu sortiert.

  • Deutlich
  • Außer
  • Schneiden
  • OfType
  • Überspringen
  • SkipWhile
  • Nehmen
  • TakeWhile
  • Woher
  • Zip (neu in .net 4)

Zerstört die Reihenfolge - wir wissen nicht, in welcher Reihenfolge die Ergebnisse erwartet werden.

  • ToDictionary
  • Nachschlagen

Reihenfolge explizit neu definieren - Verwenden Sie diese Option, um die Reihenfolge des Ergebnisses zu ändern

  • Sortieren nach
  • OrderByDescending
  • Umkehren
  • ThenBy
  • ThenByDescending

Definiert die Reihenfolge nach bestimmten Regeln neu.

  • GroupBy - Die IGrouping-Objekte werden in einer Reihenfolge ausgegeben, die auf der Reihenfolge der Elemente in der Quelle basiert, die den ersten Schlüssel jeder IGrouping erzeugt haben. Elemente in einer Gruppierung werden in der Reihenfolge ausgegeben, in der sie in der Quelle erscheinen.
  • GroupJoin - GroupJoin behält die Reihenfolge der äußeren Elemente und für jedes äußere Element die Reihenfolge der übereinstimmenden inneren Elemente bei.
  • Verbinden - behält die Reihenfolge der Elemente des Äußeren und für jedes dieser Elemente die Reihenfolge der übereinstimmenden Elemente des Inneren bei.
  • SelectMany - Für jedes Element der Quelle wird der Selektor aufgerufen und eine Folge von Werten zurückgegeben.
  • Union - Wenn das von dieser Methode zurückgegebene Objekt aufgelistet wird, listet Union die ersten und zweiten Elemente in dieser Reihenfolge auf und gibt jedes Element aus, das noch nicht ausgegeben wurde.

Edit: Ich habe Distinct zu Preserving order verschoben, basierend auf diesem Implementierung .

    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;
    }
603
Amy B

Sprechen Sie tatsächlich über SQL oder über Arrays? Anders ausgedrückt, verwenden Sie LINQ to SQL oder LINQ to Objects?

Die LINQ to Objects-Operatoren ändern ihre ursprüngliche Datenquelle nicht. Sie erstellen Sequenzen, die effektiv von der Datenquelle unterstützt werden. Die einzigen Operationen, die die Reihenfolge ändern, sind OrderBy/OrderByDescending/ThenBy/ThenByDescending - und selbst dann sind diese für gleichgeordnete Elemente stabil. Natürlich filtern viele Operationen einige Elemente heraus, aber die zurückgegebenen Elemente sind in derselben Reihenfolge.

Wenn Sie in eine andere Datenstruktur konvertieren, z. Bei ToLookup oder ToDictionary glaube ich nicht, dass die Reihenfolge zu diesem Zeitpunkt erhalten bleibt - aber das ist sowieso etwas anders. (Die Reihenfolge der Werte, die demselben Schlüssel zugeordnet sind, wird jedoch für die Suche beibehalten, glaube ich.)

31
Jon Skeet

Wenn Sie an einem Array arbeiten, scheint es, als würden Sie LINQ-to-Objects verwenden, nicht SQL. Kannst du bestätigen? Die meisten LINQ-Operationen ordnen nichts neu an (die Ausgabe erfolgt in derselben Reihenfolge wie die Eingabe). Wenden Sie daher keine andere Sortierung an (OrderBy [Absteigend]/ThenBy [Absteigend]).

[edit: wie Jon klarer ausgedrückt hat; LINQ erstellt im Allgemeinen eine neue Sequenz, wobei die ursprünglichen Daten in Ruhe gelassen werden.]

Beachten Sie, dass die Daten in ein Dictionary<,> (ToDictionary) verschlüsselt die Daten, da das Wörterbuch keine bestimmte Sortierreihenfolge einhält.

Aber die meisten üblichen Dinge (Auswählen, Wo, Überspringen, Nehmen) sollten in Ordnung sein.

7
Marc Gravell

Eine gute Antwort fand ich in einer ähnlichen Frage, die sich auf offizielle Unterlagen bezieht. Um es zu zitieren:

Für Enumerable Methoden (LINQ to Objects, gilt für List<T>) können Sie sich auf die Reihenfolge der von Select, Where oder GroupBy zurückgegebenen Elemente verlassen. Dies ist nicht der Fall für Dinge, die von Natur aus ungeordnet sind, wie ToDictionary oder Distinct.

Aus Enumerable.GroupBy Dokumentation:

Das IGrouping<TKey, TElement> Objekte werden in einer Reihenfolge ausgegeben, die auf der Reihenfolge der Elemente in der Quelle basiert, aus denen der erste Schlüssel jedes IGrouping<TKey, TElement>. Elemente in einer Gruppierung werden in der Reihenfolge ausgegeben, in der sie in source erscheinen.

Dies gilt nicht unbedingt für IQueryable -Erweiterungsmethoden (andere LINQ-Anbieter).

Quelle: Behalten die Enumerable-Methoden von LINQ die relative Reihenfolge der Elemente bei?

3
Curtis Yallop

Jede "Gruppierung nach" oder "Reihenfolge nach" ändert möglicherweise die Reihenfolge.

2
leppie

Die Frage bezieht sich hier speziell auf LINQ-to-Objects.

Wenn Sie stattdessen LINQ-to-SQL verwenden, gibt es dort keine Reihenfolge, es sei denn, Sie erzwingen eine mit etwas wie:

mysqlresult.OrderBy(e=>e.SomeColumn)

Wenn Sie dies mit LINQ-to-SQL nicht tun, kann die Reihenfolge der Ergebnisse zwischen nachfolgenden Abfragen variieren, auch bei denselben Daten, was zu einem zeitweiligen Fehler führen kann.

0
andrew pate