LINQ保证订购SelectMany?
我有一个有序的枚举数组IorderedEnumerable[] foo
我想要展平它,以便foo
的有序枚举按照它们存储在数组中的顺序连接在一起。
例如{{1,2,3},{4,5},{6}} => {1,2,3,4,5,6}
我可以通过IOrderedEnumerable bar = foo.SelectMany(x => x);
或者LINQ不能保证在展平时如何处理订单?
列表(由.net中的IEnumerable
表示)以及两个操作组成一个monad,它必须遵守monad定律 。 这两个操作在不同的语言中被赋予不同的名称,维基百科文章使用Haskell,它们return
其称为return
和>>=
(称为“bind”)。 C#调用>>=
SelectMany
,没有用于return
的内置函数。 这些名称并不重要,重要的是类型。 专门针对IEnumerable
这些是:
Return :: T -> IEnumerable SelectMany :: IEnumerable -> Func> -> IEnumerable
Return
只返回包含给定元素的1元素序列,例如
public static IEnumerable Return (T item) { return new[] { item }; }
SelectMany
已经实现为Enumerable.SelectMany
:
public static IEnumerable SelectMany(IEnumerable seq, Func> f) { ... }
SelectMany
接受一个输入序列和一个函数,该函数为输入序列的每个项生成另一个序列,并将得到的序列序列展平为一个序列。
在C#重述前两个monad法则我们有:
左派身份
Func> f = ... Return(x).SelectMany(f) == f(x)
正确的身份
IEnumerable seq = ... seq.SelectMany(Return) == seq
通过正确的身份定律, SelectMany
必须根据输入元素的顺序展平由Func
生成的每个序列。
假设它以相反的顺序扁平化它们,例如
new[] { 1, 2 }.SelectMany(i => new[] { i, -i }) == new[] { 2, -2, 1, -1 }
然后
var s = new[] { 1, 2 } s.SelectMany(Return) == new[] { 2, 1 } != s
这不符合所要求的权利身份法。
所有LINQ to Objects方法(显然, OrderBy()
和ToDictionary()
除外)将保留源排序。