假设:
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
?
答案 0 :(得分:4)
修改:如果您打算使用此功能,请参阅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
。
如果您只有热观察,您可以执行以下操作。但如果混合物中存在任何冷可观测量,则以下情况不起作用。我建议总是使用适用于冷热观察的版本。
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)));
}
答案 1 :(得分:4)
您可以合并,排序和展平序列,但这会产生很大的开销:
o1.mergeWith(o2).toSortedList().flatMapIterable(v -> v).subscribe(...)
或
o1.concatWith(o2).toSortedList().flatMapIterable(v -> v).subscribe(...)
否则,您需要编写一个相当复杂的运算符。
编辑04/06/2015:
Here is运算符可以更有效地执行此排序合并。
答案 2 :(得分:3)
我还在寻找一种支持背压但无法找到它的合并排序解决方案。因此决定基于现有的zip运算符自行实现它。
与zip类似,已排序的合并运算符首先从每个源可观察数据中收集一个项目,然后将它们放入优先级队列中,根据它们的自然顺序从中逐个发出它们。指定比较器。
您可以从GitHub中将其作为随时可用的库获取,或者只是复制/粘贴代码:
https://github.com/ybayk/rxjava-recipes
参见单元测试的使用情况。
答案 3 :(得分:1)
前一段时间在RxJava mailing list上讨论了这个问题,您可以在该主题中找到一些指向可能解决方案的链接。
答案 4 :(得分:0)
答案 5 :(得分:0)
我使用Kotlin中编写的自定义转换器的解决方案:
变形金刚:
import logging
# Only show warnings
logging.getLogger("urllib3").setLevel(logging.WARNING)
# Disable all child loggers of urllib3, e.g. urllib3.connectionpool
logging.getLogger("urllib3").propagate = False
用法:
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
}
}
})
}