【问题标题】:Diffing two Observables区分两个 Observable
【发布时间】:2017-10-27 12:37:12
【问题描述】:

我正在寻找区分两个 Observable 的最佳方法。 来自 ObservableA 的过滤值应在 ObservableB 完成后立即发出,而无需等待 ObservableA 完成。

<html>
  <head>
    <title></title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.3.0/Rx.js"></script>
    <script>

    const observable_a =  Rx.Observable.interval(2000).take(10);//0,1,2,3,4,5,6,7,8,9
    const observable_b = Rx.Observable.interval(1000).map(x=>x+3).take(5);//3,4,5,6,7

someDiffObservable(observable_a,observable_b).subscribe(console.log);//should output 0,1,2,8,9
    
    </script>
  </head>
  <body></body>
</html>

【问题讨论】:

    标签: arrays rxjs diff observable array-difference


    【解决方案1】:

    试试这个:

    const a$ = Rx.Observable.interval(2000).take(10).share();
    const b$ = Rx.Observable.interval(1000).map(x=>x+3).take(5);
    
    Rx.Observable.combineLatest(
        a$.buffer(
          b$.startWith(null).last().concat(a$)
        ), 
        b$.toArray(),  
        (aItems, bItems) => aItems.filter(a => !bItems.includes(a))
      )
      .concatMap(filteredItems => Rx.Observable.from(filteredItems))
      .subscribe(console.log);
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"&gt;&lt;/script&gt;

    【讨论】:

    • 当 observable B 为空的已完成流时,此解决方案无法正常工作。
    • 不错的收获。这是因为 last() 运算符需要至少一个值。我通过使用“startWith”运算符添加一个虚拟值来修复它
    【解决方案2】:

    目前我想出了以下函数来区分两个 observables。

    有没有更简单/更快/更好的方法来实现这一点?

    <html>
      <head>
        <title></title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.3.0/Rx.js"></script>
        <script>
    
        const observable_a =  Rx.Observable.interval(2000).take(10);//0,1,2,3,4,5,6,7,8,9
        const observable_b = Rx.Observable.interval(1000).map(x=>x+3).take(5);//3,4,5,6,7
    
        
        function observableDiff(a,b,filter) {
            if(!filter) {
                filter = (value_to_check,blacklist_array)=>{
                    return blacklist_array.indexOf(value_to_check)===-1;
                };
            }
            return Rx.Observable.create(observer=>{
                let a_values = [];
                let b_values = [];
                let a_completed = false;
                let b_completed = false;
                
                a.forEach(a_value=>{
                    if(b_completed) {
                        if(filter(a_value,b_values)) {
                            observer.next(a_value);
                        }
                    } else {
                        a_values.push(a_value);
                    }
                }).then(()=>{
                    a_completed = true;
                    if(b_completed) {
                        observer.complete();
                    }
                });
                
                b.forEach(b_value=>{
                    b_values.push(b_value);
                }).then(()=>{
                    b_completed = true;
                    a_values.forEach(a_value=>{
                        if(filter(a_value,b_values)) {
                            observer.next(a_value);
                        }
                    });
                    a_values = [];
                    if(a_completed) {
                        observer.complete();
                    }
                });
            });
        }
        
        observableDiff(observable_a,observable_b).subscribe(console.log);//0,1,2,8,9
        
        </script>
      </head>
      <body></body>
    </html>

    【讨论】:

    • 嗨,我想为未来的读者指出,虽然这个算法可以很好地找到 A 中的哪些元素在 B 中不存在(如原始帖子中所要求的那样),但它不是完全差异,因为相反是不正确的。如果交换 observable_a 和 observable_b,因为 [3, 7] 元素范围包含在 [0, 9] 范围内,则根本不会发出任何内容。真正的 diff 要么需要两个不同的输出,要么需要一个具有不同属性的对象来识别每个中存在的内容,而另一个中不存在的内容(添加或删除的内容,在常见的差异意义上)。
    • @Stéphane Seyvoz 与您的定义匹配的真实差异需要等待两个可观察对象完成。这将破坏使用可观察对象而不是数组的目的。
    猜你喜欢
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多