LINQ保证订购SelectMany?

Voi*_*tar 7 c# linq

我有一个有序的枚举数组,IorderedEnumerable<T>[] foo我想将它展平,以便有序的枚举foo按照它们存储在数组中的顺序连接在一起.

例如{{1,2,3},{4,5},{6}} => {1,2,3,4,5,6}

我可以这样做IOrderedEnumerable<T> bar = foo.SelectMany(x => x);,或者LINQ不能保证在展平时如何处理订单?

SLa*_*aks 8

所有的LINQ到对象方法(除了,很明显,OrderBy()ToDictionary())将保留源排序.


Lee*_*Lee 6

列表(由IEnumerable<T>.net 表示)以及两个操作组成一个monad,它必须遵守monad法则.这两个操作中给出了不同的语言不同的名字,维基百科的文章使用哈斯克尔这就要求他们return>>=(称为"绑定").C#调用>>= SelectMany并没有内置函数return.这些名称并不重要,重要的是类型.专门为IEnumerable<T>这些是:

Return :: T -> IEnumerable<T>
SelectMany :: IEnumerable<T> -> Func<T, IEnumerable<U>> -> IEnumerable<U>
Run Code Online (Sandbox Code Playgroud)

Return 简单地返回包含给定元素的1元素序列,例如

public static IEnumerable<T> Return<T>(T item)
{
    return new[] { item };
}
Run Code Online (Sandbox Code Playgroud)

SelectMany已经实施为Enumerable.SelectMany:

public static IEnumerable<U> SelectMany<T, U>(IEnumerable<T> seq, Func<T, IEnumerable<U>> f) { ... }
Run Code Online (Sandbox Code Playgroud)

SelectMany 采用输入序列和函数,该函数为输入序列的每个项生成另一个序列,并将得到的序列序列展平为一个.

在C#重述前两个monad法则我们有:

左派身份

Func<T, IEnumerable<U>> f = ...
Return(x).SelectMany(f) == f(x)
Run Code Online (Sandbox Code Playgroud)

正确的身份

IEnumerable<T> seq = ...
seq.SelectMany(Return) == seq
Run Code Online (Sandbox Code Playgroud)

通过正确的身份定律,SelectMany必须Func<T, IEnumerable<U>>根据输入元素的顺序展平每个生成的序列.

假设它以相反的顺序扁平化它们,例如

new[] { 1, 2 }.SelectMany(i => new[] { i, -i }) == new[] { 2, -2, 1, -1 }
Run Code Online (Sandbox Code Playgroud)

然后

var s = new[] { 1, 2 }
s.SelectMany(Return) == new[] { 2, 1 } != s
Run Code Online (Sandbox Code Playgroud)

这不符合所要求的权利身份法.

  • 你是怎么学到这个的?我有兴趣找到你获得这种信息的资源. (7认同)
  • 那么这是肯定的还是否定的? (3认同)
  • @BigEndian - 请参阅更新.关于[Haskell wiki](https://wiki.haskell.org/Monad_laws)上的monad法则也有解释.如果你想了解更多关于monad的信息,那么它们在Haskell和Scala中很普遍.C#通常不会引用它们,因为类型系统不能表达monad抽象,但你可以找到特定类型的实现(例如IEnumerable <T>,IObservable <T>,Task <T>). (2认同)