[英]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.