I am trying to implement a simple sliding window function in RxJava2, but struggling to do what I want.
My goal is to take a stream of objects, i.e.
["a", "b", "c", "d", "e"]
and apply a sliding window which will return the elements adjacent to each element.
I.e resulting in:
["a", "b"]
["a", "b", "c"]
["b", "c", "d"]
["c", "d", "e"]
["d", "e"].
I.E.
a----------------b----------------c----------------d----------------e
↓ ↓ ↓ ↓ ↓
↓ ↓ ↓ ↓ ↓
↓ ↓ ↓ ↓ ↓
↓ ↓ ↓ ↓ ↓
["a", "b"] ["a", "b", "c"] ["b", "c", "d"] ["c", "d", "e"] ["d", "e"]
I can't seem to figure out how to make this happen. A Google Groups post seems like it is on the right track, but doesn't quite get the result I need: https://groups.google.com/forum/#!topic/rxjava/k-U5BijXinU
Any ideas?
答案 0 :(得分:4)
根据您是否希望您的observable发出List<Item>
或Observable<Item>
,您可以使用buffer()
或window()
运算符。解决方案不是那么干净,但它非常简单:
Observable.fromArray("a", "b", "c", "d", "e")
.startWith("")
.buffer(3, 1)
.map(strings -> {
strings.remove("");
return strings;
})
.filter(strings -> strings.size() > 1)
返回
["a", "b"]
["a", "b", "c"]
["b", "c", "d"]
["c", "d", "e"]
["d", "e"]
答案 1 :(得分:0)
也许正如@jrook所说,这不适合标准窗口。数组大小本身并不足以知道您所在元素的哪一侧,所以我将其包含在一个简单的值类中。
这是我选择的解决方案。对于较大的流来说,它绝对不是一个好的解决方案,因为它阻止了首先读取整个可观察对象,这显然可能不适用于某些用例(在我的情况下,没关系)。
public static <R> ObservableTransformer<R, AdjacentPairing<R>> pairWithAdjacents() {
return upstream -> upstream
.toList()
.flatMapObservable(list -> {
ArrayList<AdjacentPairing<R>> pairings = new ArrayList<>(list.size());
for (int i = 0; i < list.size(); i++) {
pairings.add(AdjacentPairing.from(
i == 0 ? null : list.get(i - 1),
list.get(i),
i == list.size() -1 ? null : list.get(i + 1)));
}
return Observable.fromIterable(pairings);
});
}
@AutoValue
public static abstract class AdjacentPairing<T> {
@Nullable
public abstract T getPrevious();
public abstract T getElement();
@Nullable
public abstract T getNext();
public static <T> AdjacentPairing<T> from(@Nullable T previous, T element, @Nullable T next){
return new AutoValue_RxUtils_AdjacentPairing<>(previous, element, next);
}
}