LINQ garantisce l’ordinazione con SelectMany?

Ho una serie di enumerables ordinati IorderedEnumerable[] foo e voglio appiattirlo in modo che le enumerables ordinate di foo siano concatenate insieme nell’ordine in cui sono memorizzate nell’array.

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

Posso farlo da IOrderedEnumerable bar = foo.SelectMany(x => x); o LINQ non garantisce come viene gestito l’ordine durante l’appiattimento?

Le liste (rappresentate da IEnumerable in .net) insieme a due operazioni formano una monade, che deve obbedire alle leggi della monade . Queste due operazioni hanno nomi diversi in diverse lingue, l’articolo di wikipedia usa Haskell che le chiama return e >>= (chiamato ‘bind’). C # chiama >>= SelectMany e non ha una funzione incorporata per la return . I nomi non sono importanti e ciò che conta sono i tipi. Specializzati per IEnumerable questi sono:

 Return :: T -> IEnumerable SelectMany :: IEnumerable -> Func> -> IEnumerable 

Return restituisce semplicemente una sequenza di 1 elemento contenente l’elemento specificato es

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

SelectMany è già implementato come Enumerable.SelectMany :

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

SelectMany accetta una sequenza di input e una funzione che genera un’altra sequenza per ciascun elemento della sequenza di input e appiattisce la sequenza risultante di sequenze in una sola.

Riproponendo le prime due leggi monad in C # abbiamo:

Id quadro sinistra

 Func> f = ... Return(x).SelectMany(f) == f(x) 

Giusta id quadro

 IEnumerable seq = ... seq.SelectMany(Return) == seq 

Con la giusta legge sull’identity framework, SelectMany deve appiattire ogni sequenza generata da Func> base all’ordine degli elementi di input.

Supponiamo che li abbia appiattiti in 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 soddisferebbe la legge sull’id quadro giusta richiesta.

Tutti i metodi LINQ to Objects (tranne, ovviamente, OrderBy() e ToDictionary() ) conserveranno l’ordinamento di origine.