我有一系列重复元素,比如说:
Observable<String> source = Observable.just("A", "B", "A", "C", "C", "A");
我想按照它们的值以及它们出现的次数对它们进行分组,因此输出将成对:
{"A", 3}, {"B", 1}, {"C", 2}
基本上等同于SELECT x, COUNT(1) GROUP BY x;
我到目前为止只打电话给groupBy:
source.groupBy(x -> x, x -> 1)
但是这会将流转换为GroupedObservables,而我找不到一个如何继续使用它们的好例子。我尝试了reduce()
,但这里并不好,因为在groupBy()
之后它想要减少GroupedObservables,而不是每个组内的元素。
GroupedObservables可以实现吗?有没有其他方法可以达到预期的效果?
答案 0 :(得分:11)
以下代码:
source.groupBy(val -> val)
.flatMap(
gr -> gr.count()
.map(count -> new Pair<>(gr.getKey(), count)
)
).subscribe(System.out::println);
打印出来:
A=3
B=1
C=2
答案 1 :(得分:1)
Observable<String> source = Observable.just("A", "B", "A", "C", "C", "A");
Observable<KeyValue<String, Integer>> countStream = source
.groupBy(val -> val)
.flatMap(obs -> obs.count().flatMap(cnt -> Observable.just(new KeyValue<>(obs.getKey(), cnt))));
private static class KeyValue<K, V> {
private final K key;
private final V val;
public KeyValue(K key, V val) {
this.key = key;
this.val = val;
}
public K getKey() {
return key;
}
public V getVal() {
return val;
}
}
答案 2 :(得分:1)
另一种方法是使用collect
或collectInto
方法,如下所示。
Observable<String> source = Observable.just("A", "B", "A", "C", "C", "A");
source.collectInto(new HashMap<String, MutableInt>(), (map, elem) -> {
if (map.containsKey(elem)) {
map.get(elem).increment();
} else {
map.put(elem, new MutableInt(1));
}
}).subscribe(System.out::println);
顺便说一下,如果我们使用Reactor,collect
是这样做的暗示方式,因为在大量组的情况下,groupBy之后的flatMap将挂起。
请注意,groupBy最适用于基数较低的基数,因此请相应地选择keyMapper函数 ...
值得注意的是,当标准产生大量组时,如果组不适合在下游消耗,则可能导致挂起(例如,由于具有设置得太低的maxConcurrency参数的flatMap)。
还有一个与此相关的github issue。