假设我们有一系列数字:
0,0,0,0,1,1,2,2,2,3,4,4,4,0,0,0,0,1,1
我正在寻找可以将此序列减少为包含(element,group_count_of_this_element)的对的Rx observable。所以上面会变成:
(0,4) // first 4 "0" occurred
(1,2) // then there were two "1"s
(2,3) // then came three "2"s, one after another
(3,1) // and one occurrence of "3"
(4,3) // three "4"
(0,4) // four zeros
(2,1) // and two "1"s
我还在学习,并不能真正掌握这一点。我怀疑收集可能有所帮助,但甚至找不到一个好的例子......
答案 0 :(得分:2)
您可以通过publish
和buffer
实现具有Observable边界的效果,但我觉得它太复杂了。我发现编写一个操作符更简单,其中数据和缓冲区更改决策在一个地方:
public final class BufferUntilChanged<T, U>
implements Operator<List<T>, T> {
final Func1<? super T, U> keySelector;
public BufferUntilChanged(Func1<? super T, U> keySelector) {
this.keySelector = keySelector;
}
@Override
public Subscriber<? super T> call(Subscriber<? super List<T>> t) {
BufferUntilChangedSubscriber<T, U> parent =
new BufferUntilChangedSubscriber<>(t, keySelector);
t.add(parent);
return parent;
}
static final class BufferUntilChangedSubscriber<T, U>
extends Subscriber<T> {
final Func1<? super T, U> keySelector;
final Subscriber<? super List<T>> actual;
List<T> list;
U lastKey;
public BufferUntilChangedSubscriber(
Subscriber<? super List<T>> actual,
Func1<? super T, U> keySelector) {
this.keySelector = keySelector;
this.actual = actual;
}
@Override
public void onNext(T t) {
U u;
try {
u = keySelector.call(t);
} catch (Throwable e) {
unsubscribe();
actual.onError(e);
return;
}
boolean doRequest;
if (list == null) {
list = new ArrayList<>();
lastKey = u;
doRequest = true;
} else
if (!Objects.equals(lastKey, u)) {
actual.onNext(list);
list = new ArrayList<>();
doRequest = false;
} else {
doRequest = true;
}
list.add(t);
lastKey = u;
if (doRequest) {
request(1);
}
}
@Override
public void onError(Throwable e) {
actual.onError(e);
}
@Override
public void onCompleted() {
if (list != null) {
actual.onNext(list);
}
actual.onCompleted();
}
}
}
以下是一个使用示例:
public static void main(String[] args) {
Observable<Integer> source = Observable.from(
new Integer[] {
0,0,0,0,
1,1,
2,2,2,
3,
4,4,4,
0,0,0,0,
1,1 });
source.lift(new BufferUntilChanged<>(v -> v))
.map(list -> new Integer[] {
list.get(0), list.size()
})
.subscribe(v ->
System.out.println(Arrays.toString(v)));
}