2015-08-31 9 views
7

Ich habe ein Array von geordneten Enumerables IorderedEnumerable<T>[] foo und ich möchte es so abflachen, dass die geordneten Enumerables foo in der Reihenfolge zusammengefügt werden, in der sie im Array gespeichert sind.LINQ garantiert die Bestellung mit SelectMany?

Zum Beispiel {{1, 2, 3}, {4, 5}, {6}} => {1, 2, 3, 4, 5, 6}

Kann ich das von IOrderedEnumerable<T> bar = foo.SelectMany(x => x); oder garantiert LINQ nicht, wie die Reihenfolge beim Reduzieren behandelt wird?

Antwort

6

Listen (dargestellt durch IEnumerable<T> in .net) zusammen mit zwei Operationen bilden eine Monade, die die monad laws übernehmen muss. Diese beiden Operationen haben unterschiedliche Namen in verschiedenen Sprachen, der Wikipedia-Artikel verwendet Haskell, der sie return und nennt (genannt 'bind'). C# ruft >>= auf und hat keine integrierte Funktion für return. Die Namen sind jedoch unwichtig und was zählt, sind die Typen. Specialized für IEnumerable<T> Diese sind:

Return :: T -> IEnumerable<T> 
SelectMany :: IEnumerable<T> -> Func<T, IEnumerable<U>> -> IEnumerable<U> 

Return gibt einfach eine 1-Elementsequenz, die das gegebene Element enthält, z.B.

public static IEnumerable<T> Return<T>(T item) 
{ 
    return new[] { item }; 
} 

SelectMany ist bereits als Enumerable.SelectMany implementiert:

public static IEnumerable<U> SelectMany<T, U>(IEnumerable<T> seq, Func<T, IEnumerable<U>> f) { ... } 

SelectMany nimmt eine Eingabesequenz und eine Funktion, die für jedes Element der Eingabesequenz eine andere Sequenz erzeugt und flacht die resultierende Sequenz von Sequenzen in einem.

Neuformulierung die ersten beiden Monade Gesetze in C# haben wir:

Linke Identität

Func<T, IEnumerable<U>> f = ... 
Return(x).SelectMany(f) == f(x) 

Rechts Identität

IEnumerable<T> seq = ... 
seq.SelectMany(Return) == seq 

Durch die richtige Identität Gesetz muss SelectMany abflachen Jede Sequenz wird vongeneriertentsprechend der Reihenfolge der Eingabeelemente.

Es wird angenommen, dass sie in umgekehrter Reihenfolge, z.

new[] { 1, 2 }.SelectMany(i => new[] { i, -i }) == new[] { 2, -2, 1, -1 } 

dann

var s = new[] { 1, 2 } 
s.SelectMany(Return) == new[] { 2, 1 } != s 

, die nicht die richtige Identität Recht erfüllen würde.

+7

Wie haben Sie das gelernt? Ich wäre daran interessiert, die Ressource zu finden, wo Sie diese Art von Informationen erhalten haben. –

+0

@BigEndian aaaaaund wir werden es nie wissen :) –

+2

@BigEndian - Siehe update. Es gibt auch eine Erklärung der Monadengesetze zum [Haskell-Wiki] (https: //wiki.haskell.org/Monad_laws). Wenn Sie mehr über Monaden erfahren möchten, sind sie in Haskell und Scala weit verbreitet. C# bezieht sich normalerweise nicht auf sie, da das Typsystem die Monadenabstraktion nicht ausdrücken kann, aber Sie können Implementierungen für bestimmte Typen finden (z. B. IEnumerable , IObservable , Task ). – Lee

8

Alle Methoden von LINQ to Objects (mit Ausnahme von OrderBy() und ToDictionary()) behalten die Quellreihenfolge bei.

+0

Sogar 'OrderBy' implementiert eine stabile Sortierung auf LINQ zu Objekten :) –

Verwandte Themen