LINQ Guarantees Ordering with SelectMany?

前端 未结 2 1241
故里飘歌
故里飘歌 2020-12-17 20:48

I have an array of ordered enumerables IorderedEnumerable[] foo and I want to flatten it so that the ordered enumerables of foo are concat

相关标签:
2条回答
  • 2020-12-17 21:18

    All LINQ to Objects methods (except, obviously, OrderBy() and ToDictionary()) will preserve source ordering.

    0 讨论(0)
  • 2020-12-17 21:23

    Lists (represented by IEnumerable<T> in .net) along with two operations form a monad, which must obay the monad laws. These two operations are given different names in different languages, the wikipedia article uses Haskell which calls them return and >>= (called 'bind'). C# calls >>= SelectMany and does not have a built-in function for return. The names are unimportant however and what matters is the types. Specialised for IEnumerable<T> these are:

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

    Return simply returns a 1-element sequence containing the given element e.g.

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

    SelectMany is already implemented as Enumerable.SelectMany:

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

    SelectMany takes an input sequence and a function which generates another sequence for each item of the input sequence and flattens the resulting sequence of sequences into one.

    Restating the first two monad laws in C# we have:

    Left identity

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

    Right identity

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

    By the right identity law, SelectMany must flatten each sequence generated by the Func<T, IEnumerable<U>> according to the order of the input elements.

    Assume it flattened them in reverse order e.g.

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

    then

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

    which would not satisfy the right-identity law required.

    0 讨论(0)
提交回复
热议问题