在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
答案 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不是必要的。当然,我们可以使用range
或just(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