如何正确理解RxJava的groupBy的行为?

时间:2015-11-25 02:54:59

标签: java functional-programming rx-java reactivex

我对RxJava和FP一般都很陌生。我想编写一个代码来加入两个Observable。我们假设我们有两组整数:

  • [0..4],密钥选择器为2的模数,提供(key, value) = {(0,0), (1,1), (0,2),...}
  • [0..9],密钥选择器为3的模数,提供(key, value) = {(0,0), (1,1), (2,2), (0,3), (1,4),...}

我加入他们的步骤如下:

  1. 按键分组每组。第一组创建了两个组,其中包含键01。第二个组创建了三个组,其中包含键012
  2. 制作两组小组的笛卡尔积,总共提供6对小组,分别为:0-00-10-21-0,{{1 },1-1
  3. 仅过滤那些双方都具有相同键的对,只留下1-20-0
  4. 在每对中,制作左右组的笛卡尔积。
  5. 以下是计算笛卡尔积的辅助类:

    1-1

    以下是加入的代码:

    public class Cross<TLeft, TRight, R> implements Observable.Transformer<TLeft, R> {
        private Observable<TRight>      _right;
        private Func2<TLeft, TRight, R> _resultSelector;
    
        public Cross(Observable<TRight> right, Func2<TLeft, TRight, R> resultSelector) {
            _right = right;
            _resultSelector = resultSelector;
        }
    
        @Override
        public Observable<R> call(Observable<TLeft> left) {
            return left.flatMap(l -> _right.map(r -> _resultSelector.call(l, r)));
        }
    }
    

    但是,输出不正确:

    Observable.range(0, 5).groupBy(i -> i % 2)
            .compose(new Cross<>(Observable.range(0, 10).groupBy(i -> i % 3), ImmutablePair::new))
            .filter(pair -> pair.left.getKey().equals(pair.right.getKey()))
            .flatMap(pair -> pair.left.compose(new Cross<>(pair.right, ImmutablePair::new)))
            .subscribe(System.out::println);
    

    如果我删除包含(0,0) (0,3) (0,6) (0,9) (1,1) (1,4) (1,7) 的行,那么根本就没有结果。正确的输出就像运行这个:

    filter

    给出:

    Observable.range(0, 5)
            .compose(new Cross<>(Observable.range(0, 10), ImmutablePair::new))
            .filter(pair -> pair.left % 2 == pair.right % 3)
            .subscribe(System.out::println);
    

    有人可以解释一下这种行为吗?非常感谢。

    注意:如果您想知道,我会使用(0,0) (0,3) (0,6) (0,9) (1,1) (1,4) (1,7) (2,0) (2,3) (2,6) (2,9) (3,1) (3,4) (3,7) (4,0) (4,3) (4,6) (4,9)

1 个答案:

答案 0 :(得分:2)

问题是此设置尝试多次订阅组,这是不允许的。您会看到subscribe(System.out::println, Throwable::printStackTrace);重载的异常,始终建议使用另一个异常。这是一个固定的例子,它允许以另一层ImmutablePair为代价进行重用:

Func1<Integer, Integer> m2 = i -> i % 2;
Func1<Integer, Integer> m3 = i -> i % 3;

Observable<ImmutablePair<Integer, Observable<Integer>>> g2 = 
        Observable.range(0, 5).groupBy(m2).map(g -> new ImmutablePair<>(g.getKey(), g.cache()));
Observable<ImmutablePair<Integer, Observable<Integer>>> g3 = 
        Observable.range(0, 10).groupBy(m3).map(g -> new ImmutablePair<>(g.getKey(), g.cache()));

Observable<ImmutablePair<ImmutablePair<Integer, Observable<Integer>>, ImmutablePair<Integer, Observable<Integer>>>> x1 
= g2.compose(new Cross<>(g3, ImmutablePair::new));

Observable<ImmutablePair<ImmutablePair<Integer, Observable<Integer>>, ImmutablePair<Integer, Observable<Integer>>>> x2 
= x1.filter(pair -> pair.left.getKey().equals(pair.right.getKey()));


Observable<ImmutablePair<Integer, Integer>> o = x2.flatMap(pair -> 
pair.left.right.compose(new Cross<>(pair.right.right, ImmutablePair::new)));

o.subscribe(System.out::println, Throwable::printStackTrace);

(对于长类型,我很抱歉,如果我尝试内联它们而不是使用局部变量,那么Eclipse会有各种各样的推理问题)