假设我有两个名为source1
和source2
的可观察序列。
我希望source2
与source1
匹配,以便source2
不会重叠source1
:
// source1 = Rx.Observalble.range(...)
// source2 = Rx.Observable.range(...)
|.............| // `source1` range
|--------| // false: `source2` is overlapped
|--------| // false: `source2` is overlapped
|--------| // false: `source2` is overlapped
//|-------| // true: `source2` is not overlapped
// |--------| // true: `source2` is not overlapped
我的解决方案是使用Rx.Observable#first
和Rx.Observable#last
,如下所示:
source1 = Rx.Observable.range(100, 50)
source2 = Rx.Observable.range(150, 10)
pred1 = source1.first().zip(source2.last(), (a, b) => a >= b)
pred2 = source1.last().zip(source2.first(), (a, b) => a <= b)
// Have to use #combineLatest to get it done, don't know why
// #zip doesnt work. Uncomment the line below to check
// pred1.zip(pred2, (a, b) => a || b).subscribe(x => console.log(x))
pred1.combineLatest(pred2, (a, b) => a || b).subscribe(x => console.log(x))
我期待看到使用其他运营商的解决方案,例如#reduce
,#scan
,#flatMap
,#concatMap
或#filter
。
原因是,上面的例子只比较了两个范围。如果我需要检查范围数组,如果它们彼此重叠,该怎么办?考虑在这种情况下有用的reducer
。
// `array_of_range` could be an array of observable sequences
let source = Rx.Observalbe.fromArray(array_of_range)
source.scan((prev, curr) => {
// Do magic here
}, false)
.subscribe(x => console.log(x)) //=> Check if any two ranges in the `source` are overlapped or not
并且如果范围重叠,如何transform
这些范围成为最佳的较小新范围,以便它们不会相互重叠。我知道这不是微不足道的答案,所以任何建议都表示赞赏!
更新01: 感谢@joneshf,第一个问题可以解决如下:
Rx.Observable.merge(
Rx.Observable.range(0, 10),
Rx.Observable.range(11, 20),
Rx.Observable.range(21, 25)
)
.scan(({intersected, set}, n) => ({intersected: set.has(n), set: set.add(n)}),
{intersected: false, set: new Set()}
)
.pluck('intersected')
.reduce((prev, curr) => prev || curr)
.subscribe(x => x ? ‘There was an intersection’ : ‘No intersection’)
欢迎任何进一步的讨论!
答案 0 :(得分:0)
您可以按索引分组(使用 zip
)
zip(range(1, 10), range(5, 10), range(10, 10)).subscribe(z => {
console.log(z);
});
//=> [ 1 , 5 , 10 ]
//=> [ 2 , 6 , 11 ]
//=> [ 3 , 7 , 12 ]
//=> [ 4 , 8 , 13 ]
//=> [ 5 , 9 , 14 ]
//=> [ 6 , 10, 15 ]
//=> [ 7 , 11, 16 ]
//=> [ 8 , 12, 17 ]
//=> [ 9 , 13, 18 ]
//=> [ 10, 14, 19 ]
然后您可以重建每个范围当且仅当它的数字以前从未见过:
输入 | 第一个 rg。 | 第二个rg。 | 第三个rg。 | 主集 |
---|---|---|---|---|
[1, 5, 10] | [1] | [5] | [10] | 设置{1 5 10} |
[2, 6, 11] | [1, 2] | [5, 6] | [10, 11] | 设置{1 2 5 6 10 11} |
[3, 7, 12] | [1, 2, 3] | [5, 6, 7] | [10, 11, 12] | 设置{1 2 3 5 6 7 10 11 12} |
… | … | … | … | … |
const solution$ =
zip(range(1, 10), range(5, 10), range(10, 10)).pipe(
reduce(([rg, st], ns) => {
ns.forEach((n, i) => {
if (!st.has(n)) {
rg[i] ??= [];
rg[i].push(n);
st.add(n);
}
});
return [rg, st];
}, [[], new Set])
);
solution$.subscribe(([rg]) => {
console.log('Optimal ranges:',
rg.map(r => `[${r[0]}-${r[r.length-1]}]`).join(', '));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.2.0/rxjs.umd.min.js" integrity="sha512-MlqMFvHwgWJ1vfts5fdC2WzxDaIXWfYuAd9Tb2lobtF61Gk+HIRDrbtxgasBSM9lZgOK9ilwK9LqFIYEV+k0IA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const {zip, range} = rxjs;
const {reduce} = rxjs.operators;
</script>