RxJava 学习笔记<七> Aggregation

我们已经看到了如何切掉我们不想要的 sequence 的部分,如何获得单个值,以及如何检查 sequence 的内容。这些东西可以看作是关于包含 sequence 的推理。现在,我们将看到如何使用 sequence 中的数据来导出新的有意义的值。

我们将在这里看到的方法类似于所谓的质变(catamorphism)。在我们的例子中,这意味着方法消耗序列中的值并将它们组合成一个值。但是,它们并不严格满足定义,因为它们不返回单个值。相反,它们返回一个 observable 有望发出单一值。

如果你已经阅读了所有的例子,你应该注意到一些重复。为了消除这种情况并将重点放在重要的事情上,我们现在将引入一个自定义 Subscriber ,我们将在示例中使用它

这是一个非常基本的实现,它将每个事件打印到控制台。

count

我们的第一种方法是计数。它的用途与大多数Java容器中的长度和大小相同。此方法将返回一个可观察到的值,该值将等待 sequence 完成并发出所遇到的值的数目。

    输出:

对于可能超过标准整数容量的序列也有CountLong。

first

First将返回一个 observable,该值仅发出序列中的第一个值。它与Take(1)类似,只是如果没有找到,它将发出java.util.NoSuchElementException。如果使用接受谓词的重载,则返回与谓词匹配的第一个值。

输出:

为了规避 java.util.NoSuchElementException 异常,我们可以使用 firstOrDefault 方法来设置默认值。

last

last 和 lastOrDefault 工作方式与 first 相同,只是返回的项是序列完成前的最后一项。当将重载与谓词一起使用时,返回的项是与谓词匹配的最后一项。

single

Single 发出序列中唯一的值,或者在给定时唯一满足谓词的值。它与第一个和最后一个不同之处在于,它不会忽略多个匹配。如果找到多个匹配项,它将发出错误。它可以用来断言序列必须只包含一个这样的值。

记住,Single 必须检查整个序列,以确保您的断言。

输出:

通过前面的方法,我们知道可以设置默认值 singleOrDefault

Custom aggregators

到目前为止,我们在本章中看到的方法似乎与前几章中的方法没有什么不同。我们现在将看到两种非常强大的方法,它们将极大地扩展我们可以利用 observable 来做的事情。到目前为止,我们看到的许多方法都可以使用这些方法来实现。

reduce

您可能听说过[MapReduce](https://en.wikipinea.org/wiki/MapReduce)中的Report。或者,您也可以将其命名为“聚合”、“累积”或“折叠”。一般的想法是,通过一次合并两个值,从多个值中产生一个值。在其最基本的重载中,您所需要的只是一个将两个值组合成一个值的函数。

public final Observable<T> reduce(Func2<T,T,T> accumulator)

这最好用一个例子来解释。这里我们将计算一个整数序列的和:0+1+2+3+4+...。我们还将计算不同示例的最小值;

输出:

Rx中的 reduce 与并行系统中的“reduce”并不相同。在并行系统中,它意味着值对可以任意选择,从而使多台机器可以独立工作。在Rx中,累加器函数从左到右依次应用(如图所示)。每次,累加器函数将上一步的结果与下一个值结合起来。这在另一个重载中更为明显:

public final <R> Observable<R> reduce(R initialValue, Func2<R,? super T,R> accumulator)

累加器返回的类型与可观察到的类型不同。累加器的第一个参数是前一个累加过程的部分结果,第二个参数是下一个值。要开始这个过程,需要提供一个初始值。我们将通过重新实现Count来证明这一点的有用性。

输出:

我们从累加器0开始,因为我们已经计算了0项。每当新项目到达时,我们返回一个新的累加器,该累加器增加了一个。最后一个值对应于源序列中的元素数。

reduce 可用于实现发出单个值的大多数运算符的功能。它不能实现在源完成之前发出值的行为。因此,您可以使用 reduce 实现 last,但 all 的实现不会完全像原来的那样。

scan

scan 非常类似于 reduce,关键的区别是 scan 将发出所有中间结果。

public final Observable<T> scan(Func2<T,T,T> accumulator)

在我们的求和示例中,使用 Scan 将生成一个运行求和。

输出:

Scan 比 reduce 更通用,因为 Reduce 可以用Scan实现:REPLE(Acc)=Scan(Acc).Take Lasts()

scan 在源发出时发出,不需要源来完成。我们通过实现返回运行最小值的可观察值来证明:

输出:

Aggregation to collections

没有什么可以阻止你的累加器成为一个集合。您可以使用r educe 将Observable<T><转List<T>中。

输出:

上面的代码在形式上有一个问题:reduce 是一个函数折叠,而这样的折叠不应该用于可变累加器。如果我们以“正确”的方式执行此操作,则必须为每个新项创建ArrayList<Integer>的新实例,如下所示:

collect

为每项新项目创建新集合的性能是不可接受的。出于这个原因,Rx 提供了 collect 操作符,它与 reduce 一样,只使用可变累加器。通过使用 collect ,您不遵循不可修改的约定,并且您还简化了代码:

输出:

通常,您不必手动收集值。RxJava提供了多种操作符,用于将序列收集到容器中。这些聚合器返回一个operators集合,当它准备好时,它将发出相应的集合,就像我们在这里所做的那样。接下来,我们将看到这样的聚合器。

toList

输出:

toSortedList

toSortedList 工作方式类似于 toList,顾名思义,就是结果是排序的。

输出:

toMap

toMap 把我们的 sequence 转换成 Map<TKey,T> 

输出:

groupBy

这是Rx对Multimap的操作方式。对于每个值,它计算一个键,并根据该键将值分组为单独的可观测值。

输出:

nest

当处理nested observables,Nest 操作符变得很有用。它允许你把一个 non-nested observable  变成一个nested 。

输出:

原文链接:

https://github.com/Froussios/Intro-To-RxJava/blob/master/Part%202%20-%20Sequence%20Basics/4.%20Aggregation.md

有什么讨论的内容,可以加我微信公众号:

猜你喜欢

转载自my.oschina.net/u/2277632/blog/1663222