javascript - 如何解决 RxJS 范围重叠问题?

标签 javascript rxjs

假设我有两个名为 source1source2 的 Observable Sequence。 我想将 source2source1 匹配,这样 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#firstRx.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

原因是,上面的例子只是比较了两个范围。如果我有一个 array of range 需要检查它们是否相互重叠怎么办?考虑在这种情况下会有所帮助的 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

并且如果范围重叠,如何将这些范围转换为最佳的更小的新范围,以便它们不会相互重叠。我知道这不是微不足道的答案,所以任何建议都将不胜感激!

更新 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’)

欢迎进一步讨论!

最佳答案

您可以按索引分组(使用 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 ]

然后你可以重建每个范围当且仅当它的数字以前从未见过:

<表类="s-表"> <头> 输入 第一个 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>

关于javascript - 如何解决 RxJS 范围重叠问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33748596/

相关文章:

javascript - 无法使用 javascript 抓取 iframe 和框架集中的框架(域相同)

Angular 7 属性 'share' 在可观察类型中不存在

angular - 将生成的 forkJoin 数组传递给 Angular 中的多个组件

RxJS 教程不需要熟悉响应式(Reactive)编程概念或 Rx .NET?

rxjs - Angular 调用异步管道使 http 调用多次

javascript - 2 个相关流的安全更新

javascript - 一个函数改变另一个函数的局部变量?

javascript - 检查并突出显示表格中的当前日期

javascript - 在单独的路由中使用 useRef 响应滚动导航

javascript - 对象不断丢失其更具体的类型?