2015-08-31 4 views
7

Ho una serie di enumerables ordinati IorderedEnumerable<T>[] foo e voglio appiattirlo in modo che le enumerables ordinate di foo siano concatenate insieme nell'ordine in cui sono memorizzate nell'array.LINQ garantisce l'ordinazione con SelectMany?

Ad esempio {{1, 2, 3}, {4, 5}, {6}} => {1, 2, 3, 4, 5, 6}

Posso fare questo IOrderedEnumerable<T> bar = foo.SelectMany(x => x); o LINQ non garantisce come viene gestito l'ordine durante l'appiattimento?

risposta

6

Liste (rappresentate da IEnumerable<T> in .net) insieme a due operazioni formano una monade, che deve obbedire allo . Queste due operazioni hanno nomi diversi in diverse lingue, l'articolo di wikipedia usa Haskell che li chiama return e >>= (chiamato "bind"). C# chiama >>=SelectMany e non ha una funzione incorporata per return. I nomi non sono importanti e ciò che conta sono i tipi. Specializzato per IEnumerable<T> questi sono:

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

Return restituisce semplicemente una sequenza 1 elementi contenente dell'elemento dato esempio

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

SelectMany è già implementata come Enumerable.SelectMany:

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

SelectMany prende una sequenza di immissione e una funzione che genera un'altra sequenza per ogni elemento della sequenza di input e appiattisce la sequenza risultante di sequenze in uno.

Riaffermando le prime due leggi monade in C# che abbiamo:

identità Sinistra

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

identità destro

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

Per la legge dell'identità destra, SelectMany deve appiattire ogni sequenza generata dallo Func<T, IEnumerable<U>> in base all'ordine degli elementi di input.

Si supponga di appiattirli nell'ordine inverso, ad es.

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

poi

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

che non avrebbe soddisfatto la legge giusta identità richiesto.

+7

Come hai imparato questo? Sarei interessato a trovare la risorsa in cui hai ottenuto questo tipo di informazioni. –

+0

@BigEndian aaaaa e non lo sapremo mai :) –

+2

@BigEndian - Guarda l'aggiornamento. C'è anche una spiegazione delle leggi della monade sul [wiki Haskell] (https: //wiki.haskell.org/Monad_laws). Se vuoi saperne di più sulle monadi in generale, allora sono pervasive in Haskell e Scala. Normalmente, C# non fa riferimento ad essi poiché il sistema di tipi non può esprimere l'astrazione della monade ma è possibile trovare implementazioni per tipi particolari (ad esempio IEnumerable , IObservable , Task ). – Lee

8

Tutti i metodi LINQ to Objects (ad eccezione, ovviamente, OrderBy() e ToDictionary()) conservano l'ordinamento di origine.

+0

Anche 'OrderBy' implementa un ordinamento stabile su LINQ agli oggetti :) –