IEnumerable<T> vs. IObservable<T> SelectMany
值得注意的是IEnumerable<T>SelectMany和IObservable<T>SelectMany之间的区别,IEnumerable<T>基于Pull并且阻塞线程,这意味着当一个IEnumerable<T>进程中有SelectMany,将会传递一个时间给selector方法,并等待直到selector方法从源请求(pulling)下一个值。
想象一个值为[1,2,3]的IEnumerable<T>类型源队列,与SelectMany一起进行处理后返回一个[x*10, (x*10)+1, (x*10)+2]的队列,也就是 [队列[10,11,12], 队列[20,21,22], 队列[30,31,32]]:
我们对下面的代码使用GetSubValues方法:
输出将合并为[10,11,12,20,21,22,30,31,32]:
10
11
12
20
21
22
30
31
32
与IObservable<T>队列不同的是,调用SelectMany的selector方法是不阻塞的,并且结果队列可以随着时间的推移产生值。这意味着后续的子队列可以继续重叠。下面我们将用图例来演示这种异步数据。
Visualizing sequences
在使用文字图来进行演示之前有几点你需要知道:
- 水平线代表队列
- 时间向右移动
- 消息用字符表示
- '0'为OnNext
- 'X'为OnError
- '|' 为OnCompleted
- 多条水平线代表多个并行的队列
这是一个有三个值的完成了的队列的图例:
--0--0--0-|
这是一个有4个值后出错了的队列的图例:
--0--0--0--0--X
现在回到SelectMany的例子,我们可以通过使用实际的值来代替符号“0”来图例化输入队列,下面的图例代表队列[1,2,3],间隔为3秒(包括字符“-”在内每个字符相当于于1秒)
--1--2--3|
这里我们看到第一个值,它产生了间隔为4秒的队列[10,11,12](初始值是立刻产生的)。
1---1---1|
0 1 2|
由于值由两个数字组成,它们覆盖2行(比如第一个值10,它在图例中由蓝色第一行的1和蓝色第二行的0组成)。我们为selector方法产生的每一个队列添加两行,并用颜色区别开来以便查看:
现在我们可以图例化源队列源其子队列。我们还可以推断出SelectMany操作的输出。我们只需要将各个子队列中的值填到最底端的结果行即可:
如上图所见,由于第一个值是立即产生的,所以第一个输出的值是10;而子队列每个值间隔4秒,源队列每个值只间隔3秒,所以第二个值是第2个子队列立即产生的第一个值20,然后才是11,之后类推。我们可以做个例子验证一下:
输出与图例相符:
SelectMany-->10
SelectMany-->20
SelectMany-->11
SelectMany-->30
SelectMany-->21
SelectMany-->12
SelectMany-->31
SelectMany-->22
SelectMany-->32
SelectMany completed
Select方法与query comprehension语法相关,但SelectMany则不那么相关。仅仅使用Select的简单实现如下:
如果我们想添加一个简单的WHERE子句,我们可以这样做:
添加SelectMany到查询,需要添加一个from从句:
使用query comprehension语法的优点是可以轻松的访问查询范围中的其他变量:
Output
SelectMany-->{ i = 2, j = 20 }
SelectMany-->{ i = 4, j = 40 }
SelectMany-->{ i = 2, j = 21 }
SelectMany-->{ i = 4, j = 41 }
SelectMany-->{ i = 2, j = 22 }
SelectMany-->{ i = 4, j = 42 }
SelectMany completed
深入后发现大多数操作实际上是专业化的高阶函数概念,可以分为ABC三类:
Anamorphism, aka:
- Ana
- Unfold
- Generate
Bind, aka:
- Map
- SelectMany
- Projection
- Transform
Catamorphism, aka:
- Cata
- Fold
- Reduce
- Accumulate
- Inject
暂无关于此日志的评论。