RxJs中的Observable.expand()的RxJava等价物是什么?

时间:2014-11-14 10:39:54

标签: rx-java rxjs

在RxJs中有一个名为Observable.expand的方法,它可以递归地扩展带有转换函数的序列。

例如,

Rx.Observable.return(0).expand(function (x) { return Rx.Observable.return(x+1); }) 

将发出所有整数

但是,我在RxJava中找不到这个方法。 RxJava中是否有其他方法可以实现类似的目标?

有关exapand()的更详细说明,请参阅https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/expand.md

2 个答案:

答案 0 :(得分:2)

嗯,你提供的例子可以简化为:

Observable.range(0, Integer.MAX_VALUE)

但我假设你真的想要做一些更复杂的事情。 scan与您正在寻找的内容不同,但它可以执行类似的操作,我们可以使用它来制作可以重复使用的Transformer,类似于展开。

scan的主要区别在于它在每一步都需要一个新的输入值,但是,就像展开一样,它保留了之前的值。我们可以通过忽略新的输入值来实现。因为扫描类似于扩展,所以我将从一个具有一些相当大缺陷的scan示例开始,然后探索更好的选择。

public class Expand<T, T> implements Transformer<T, T> {
  private final Func1<T, T> expandFunc;

  public Expand(final Func1<T, T> expandFunc) {
    this.initialValue = initialValue;
    this.expandFunc = expandFunc;
  }

  @Override
  public Observable<T> call(Observable<T> source) {
    // Here we treat emissions from the source as a new 'initial value'.

    // NOTE: This will effectively only allow one input from the source, since the
    // output Observable expands infinitely. If you want it to switch to a new expanded
    // observable each time the source emits, use switchMap instead of concatMap.
    return source.concatMap(new Func1<T, Observable<T>>() {

      @Override
      public Observable<T> call(T initialValue) {
        // Make an infinite null Observable, just for our next-step signal.
        return Observable.<Void>just(null).repeat()
            .scan(initialValue, new Func2<T, Void, T>() {

              @Override
              public T call(final T currentValue, final Void unusedSignal) {
                return expandFunc.call(currentValue);
              }

            });
      }

    });
  }
}

要使用该变换器,让我们创建一个方法,该方法采用当前数字,加1,并将其平方。

Observable.just(1).compose(new Expand(new Func1<Integer, Integer>() {

  @Override
  public Integer call(final Integer input) {
    final Integer output = input + 1;
    return output * output;
  }

});

无论如何,你可能已经注意到了这种方法的一些主要尴尬点。首先,有关于switch和concatMap的事情,以及它如何将一个项目从Observable输出转换为无限链。其次,整个&#39; Void&#39;信号Observable不是必要的。当然,我们可以使用rangejust(1).repeat()或其他许多东西,但它们最终会被扔掉。

这是一种可以更清晰,更递地模拟它的方法。

public static <T> Observable<T> expandObservable(
    final T initialValue, final Func1<T, T> expandFunc) {
  return Observable.just(initialValue)
      .concatWith(Observable.defer(new Func0<Observable<T>>() {

        @Override
        public Observable<T> call() {
          return expandObservable(expandFunc.call(initialValue), expandFunc);
        }

      });
}

因此,在这个例子中,每个递归传递输出当前值(在每一步上展开,并在下一步结束。defer用于保持无限递归不会立即发生,因为它没有&#39 ; t调用代码创建Observable直到它订阅。使用它看起来像这样:

expandObservable(1, new Func1<Integer, Integer>() {

  @Override
  public Integer call(final Integer input) {
    final Integer output = input + 1;
    return output * output;
  }

}).subscribe(/** do whatever */);

因此,非常像compose示例,但实现更加整洁和清洁。

希望有所帮助。

答案 1 :(得分:0)

我认为您正在寻找map

https://github.com/ReactiveX/RxJava/wiki/Transforming-Observables#map

numbers = Observable.from([1, 2, 3, 4, 5]);

numbers.map({it * it}).subscribe(
  { println(it); },                          // onNext
  { println("Error: " + it.getMessage()); }, // onError
  { println("Sequence complete"); }          // onCompleted
);

1
4
9
16
25
Sequence complete