【问题标题】:Filter an observable by an observable通过可观察对象过滤可观察对象
【发布时间】:2016-07-23 20:45:53
【问题描述】:

让我们考虑以下简化的情况:

  • 我们有一个 Observable apples 类型的 Observable
  • 每个 Apple 对象都有一个方法 isRotten(),它返回一个 Observable 类型的 observable,它保证发出至少一个布尔值。

我想过滤可观察到的苹果,这样烂苹果就不会通过过滤器。更准确地说,当且仅当 A.isRotten() 发出的第一项为假时,苹果 A 通过过滤器。实现此过滤器的最佳方法是什么?

经过一番思考,我可以想出这个:

apples
    .concatMap(apple => 
        apple.isRotten()
            .first()
            .filter(bool => bool)
            .map(bool => apple))

这是用 javascript 编写的。 ( ... => ... 是一个函数)。这行得通,但我认为它相当冗长且难以理解。有没有更好的方法来做这种事情?

【问题讨论】:

    标签: rxjs reactivex


    【解决方案1】:

    您所拥有的一切都很好,而且,我想不出更简洁的方式来做到这一点。如果乱序的苹果不是问题,我可能会使用flatMap 而不是concatMap

    如果可读性对您来说是个问题,只需将实现移到它的一个函数中(例如,filterObservable 接受一个函数,该函数接受一个值并返回一个 IObservable<bool>

    【讨论】:

    • 感谢您的回答,我希望像 filterObservable 这样的东西存在。但我想我必须自己实现它。
    【解决方案2】:

    实现这一点的一种方法是这样的,抱歉我没能适应水果过滤:

    const orders$: Observable<Order[]> = searchOrders(...);
    
    const filteredOrders$ = orders$.pipe(switchMap((orders) => {
    
        // take all orders and determine visibility based on an observable
        const visibilityRules = orders.map(o => {
    
            return {                    
                order: o,
                visible$: o.isPaidFor$   // this is an observable on an Order object
            };
        });
    
        const filtered = visibilityRules.map(o => o.visible$.pipe(map(visible => visible ? o.order : undefined )));
        return (filtered.length == 0) ? of([]) : combineLatest(filtered).pipe(map(combined => combined.filter(x => x != undefined)));
    
    }));
    

    这会过滤“paidFor”订单,并在每次订单变为已付款或未付款时发出一个新数组。

    注意:如果isPaidFor$ observable 在搜索之间不能改变,那么整个练习是没有意义的,因为没有理由提供这样的“实时视图”。只有当 observable 可以在搜索结果之间实际发生变化时,这才有意义。

    如果需要,这可以扩展到更复杂的规则(例如添加过滤复选框) - 这就是我创建中间 visibilityRules 数组的原因 - 严格来说只是为了可读性。

    【讨论】:

      【解决方案3】:

      你可以这样做:

      var seq = Rx.Observable.from([1, 2, 3, 4, 5, 6])
          .filter(x => {
              let isRotten = true;
              Rx.Observable.just(x % 2 === 0)
                  .first()
                  .subscribe(val => isRotten = val);
      
              if (isRotten) {
                  return x;
              }
          });
      
      seq.subscribe(x => console.log(x));
      

      【讨论】:

      • 你确定吗?我认为这不起作用,因为 x.isRotten() 不返回布尔值,它返回一个发出布尔值的 Observable。
      • 我做了以下小提琴,它验证过滤器运算符不适用于 Observables。 jsfiddle.net/pgcrwauj
      • @WardBeullens 请查看更新后的代码。起初我没有得到你的问题。
      • 很抱歉,但我不认为你的方法有什么好处。它只有效(老实说,我很惊讶它完全有效),因为 Observable.just 解决得非常快。如果您添加延迟(好像该方法必须执行 http 调用或其他操作),它将不再有效。 jsfiddle.net/8qu2c29j
      • @WardBeullens 如果代码必须做额外的工作来获得内部的 Observable,那么我会做不同的事情。具体来说,我会查看 map 以获取立即值 + 原始值,然后对 map 的输出进行过滤。
      猜你喜欢
      • 2023-04-08
      • 1970-01-01
      • 2012-10-19
      • 2021-09-22
      • 1970-01-01
      • 2018-11-23
      • 1970-01-01
      • 2019-09-09
      • 2011-06-17
      相关资源
      最近更新 更多