组Observables然后按计数过滤

时间:2015-12-05 21:35:30

标签: javascript reactive-programming rxjs

我在过滤基于groupBy observable的Observable时遇到问题。 以下是基于groupBy()文档的示例: var code = [   {keyCode:38},// up   {keyCode:38},// up   {keyCode:40},//向下   {keyCode:40},//向下   {keyCode:37},//左   {keyCode:39},//对   {keyCode:37},//左   {keyCode:39},//对   {keyCode:66},// b   {keyCode:65} // a ]。 var source = Rx.Observable.from(codes)   。通过...分组(     function(x){return x.keyCode; },     function(x){return x.keyCode; }   )   .flatMap(obs =>     obs.count()       .filter(x => x> 1)       .flatMap(obs.toArray())   ) source.subscribe(的console.log) 返回: [] [] [] [] 因此,Observables正在被过滤,但它们的价值已经消失。

2 个答案:

答案 0 :(得分:2)

将可观察对象作为单个对象(例如,数组)而非作为异步值的序列进行推理是很棘手的。这里发生的是:

  • 您接受obs观察,然后将count应用于

    count将等待observable完成并输出一个值,元素数量然后完成。

  • 您过滤了该值,但之后您将toArray应用于已经完成的obs。这就是你得到一个空阵列的原因。

所以这里的问题是相同的obs变量在不同的时间是不同的,所以当你在程序的不同点重用相同的变量时,你不能避免必须推理时间。

现在,如果您想将计数编号输出到subscribe,您应该可以直接编写obs.count().filter(x => x > 1).toArray()而不是现在的编号。除了observable之外,flatMap接受promise和数组作为选择器函数的返回值:

比照https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/selectmany.md

更新: 考虑到这些评论,这就是我提出的(待测试):

var source = Rx.Observable
    .from(codes)
    .scan(function ( acc, code ) {
            acc[code] = acc[code] + 1;
            acc.latest = code;
            return acc;
          }, {})
    .filter(function ( acc ) {return acc[acc.latest] > 1;})
    .flatMap(function ( acc ) {return acc[acc.latest] == 2? Rx.Observable.repeat(acc.latest, 2) : Rx.just(acc.latest);})

如果您可以等待处理所有值,则可以在过滤器后停止上述操作并添加.last()。这将为您提供具有所有值计数的最后一个累加器。从那里你可以做你想做的事。

答案 1 :(得分:0)

我找到了类似于user3743222's answer

的解决方案
  var filtered = source
    .flatMap(obs => {
      var accumulated = obs.scan((a,b) => a.concat(b), [])
      return obs
        .scan((a) => a + 1, 0)
        .filter(i => i > 1)
        .withLatestFrom(
          accumulated, 
          (a, b) => Rx.Observable.from(b)
        )
    })
    .flatMap(d => d)
    .subscribe(d => console.log(d))