[英]How to merge two sorted Observables into a single sorted Observable?
鑒於:
Integer[] arr1 = {1, 5, 9, 17};
Integer[] arr2 = {1, 2, 3, 6, 7, 12, 15};
Observable<Integer> o1 = Observable.from(arr1);
Observable<Integer> o2 = Observable.from(arr2);
如何獲得一個包含1, 1, 2, 3, 5, 6, 7, 9, 12, 15, 17
的 Observable ?
編輯:如果您要使用它,請參閱 the_joric 的評論。 有一個邊緣情況沒有處理,我看不到快速修復它的方法,所以我現在沒有時間修復它。
這是 C# 中的解決方案,因為您有system.reactive
標記。
static IObservable<int> MergeSorted(IObservable<int> a, IObservable<int> b)
{
var source = Observable.Merge(
a.Select(x => Tuple.Create('a', x)),
b.Select(y => Tuple.Create('b', y)));
return source.Publish(o =>
{
var published_a = o.Where(t => t.Item1 == 'a').Select(t => t.Item2);
var published_b = o.Where(t => t.Item1 == 'b').Select(t => t.Item2);
return Observable.Merge(
published_a.Delay(x => published_b.FirstOrDefaultAsync(y => x <= y)),
published_b.Delay(y => published_a.FirstOrDefaultAsync(x => y <= x)));
});
}
這個想法總結如下。
當a
發出值x
,我們將其延遲,直到b
發出值y
使得x <= y
。
當b
發出值y
,我們將其延遲,直到a
發出值x
使得y <= x
。
如果您只有熱的 observables,您可以執行以下操作。 但是,如果混合中存在任何冷可觀察值,則以下內容將不起作用。 我建議始終使用適用於熱和冷 observables 的版本。
static IObservable<int> MergeSortedHot(IObservable<int> a, IObservable<int> b)
{
return Observable.Merge(
a.Delay(x => b.FirstOrDefaultAsync(y => x <= y)),
b.Delay(y => a.FirstOrDefaultAsync(x => y <= x)));
}
您可以對序列進行合並、排序和展平,但這會產生很大的開銷:
o1.mergeWith(o2).toSortedList().flatMapIterable(v -> v).subscribe(...)
或者
o1.concatWith(o2).toSortedList().flatMapIterable(v -> v).subscribe(...)
否則,您需要編寫一個相當復雜的運算符。
2015 年 4 月 6 日編輯:
這是一個更有效地進行排序合並的運算符。
我也在尋找一種支持背壓的合並排序解決方案,但找不到它。 所以決定根據現有的 zip 運算符松散地自己實現它。
與 zip 類似,排序合並運算符首先從每個源 observable 中收集一個項目,然后將它們放入一個優先級隊列,從優先級隊列中根據它們的自然順序或指定的比較器將它們一個一個地發出。
你可以從 GitHub 上獲取它作為一個隨時可用的庫,或者只是復制/粘貼代碼:
https://github.com/ybayk/rxjava-recipes
有關用法,請參閱單元測試。
前段時間在RxJava 郵件列表中討論過這個問題,您會在該線程中找到一些指向可能解決方案的鏈接。
只是合並和排序怎么樣?
@Test
public void testMergeChains() {
Observable.merge(Observable.from(Arrays.asList(1, 2, 13, 11, 5)), Observable.from(Arrays.asList(10, 4, 12, 3, 14, 15)))
.collect(ArrayList<Integer>::new, ArrayList::add)
.doOnNext(Collections::sort)
.subscribe(System.out::println);
}
您可以在此處查看更多示例
我使用 Kotlin 編寫的自定義轉換器的解決方案:
變壓器:
fun <T> orderedMerge(f2: Flowable<T>, c: Comparator<T>) = FlowableTransformer<T, T> { f1 ->
val f1Iterator = f1.blockingIterable(1).iterator()
val f2Iterator = f2.blockingIterable(1).iterator()
Flowable.generate(
Callable { null as T? to null as T? },
BiFunction { (lastF1: T?, lastF2: T?), emitter: Emitter<T> ->
when {
lastF1 != null && f2Iterator.hasNext() -> {
val nextF2 = f2Iterator.next()
if (c.compare(lastF1, nextF2) <= 0) {
emitter.onNext(lastF1)
null to nextF2
} else {
emitter.onNext(nextF2)
lastF1 to null
}
}
lastF1 != null -> {
emitter.onNext(lastF1)
null to null
}
lastF2 != null && f1Iterator.hasNext() -> {
val nextF1 = f1Iterator.next()
if (c.compare(nextF1, lastF2) <= 0) {
emitter.onNext(nextF1)
null to lastF2
} else {
emitter.onNext(lastF2)
nextF1 to null
}
}
lastF2 != null -> {
emitter.onNext(lastF2)
null to null
}
f1Iterator.hasNext() && f2Iterator.hasNext() -> {
val nextF1 = f1Iterator.next()
val nextF2 = f2Iterator.next()
if (c.compare(nextF1, nextF2) <= 0) {
emitter.onNext(nextF1)
null to nextF2
} else {
emitter.onNext(nextF2)
nextF1 to null
}
}
f1Iterator.hasNext() -> {
val nextF1 = f1Iterator.next()
emitter.onNext(nextF1)
null to null
}
f2Iterator.hasNext() -> {
val nextF2 = f2Iterator.next()
emitter.onNext(nextF2)
null to null
}
else -> {
emitter.onComplete()
null to null
}
}
})
}
用法:
val f1 = listOf(1, 2, 3, 7, 10, 11, 11, 20).toFlowable()
val f2 = listOf(3, 4, 5, 8, 15, 16).toFlowable()
val ff = f1.compose(orderedMerge(f2, Comparator.naturalOrder()))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.