ReactiveX:从可观察值中滤除数字,使总数永远不会低于零

时间:2018-08-16 08:46:41

标签: javascript rxjs reactive-programming reactivex

以下RxJs代码显示输入列表中的数字和运行总计:

let inputs = [10, 10, -30, 10, -30, 50, -25, -30, 10]

let obs$ = Rx.Observable.from(inputs)
let totals$ = obs$.scan((acc, next) => acc + next, 0)
obs$.subscribe(x => console.log('x:', x));
totals$.subscribe(x => console.log("total:", x))

totals$将发出:10、20,-10、0,-30 ...

我想以某种方式转换obs$的可观察性,以使生成的totals$永远不会发出负数。

也就是说,在这种情况下,首个和最后一个“ -30”都应被过滤掉:

otherObs$:10、10、10,-30、50,-25、10

totals$:10、20、30、0、50、25、35

edit:请注意,我对修改后的otherObs$可观察到的数据感兴趣,即,原始输入数字的序列已被过滤掉(obs$实际上将包含更多数据,所以我确实需要原始元素;“值”仅是过滤的关键)。 totals$仅用于显示正在发生的事情。

2 个答案:

答案 0 :(得分:1)

您可以通过将逻辑整合到.scan()内部的reduce函数中轻松实现这一目标:

let total$ = obs$.scan((acc, next) => {
    if (acc + next < 0) { //less than zero, don't take in the current number
        return acc;
    }
    return acc + next; //all is good, continue to add next
}, 0)

甚至在一个班轮中:

let totals$ = obs$.scan((acc, next) => (acc + next < 0 ? acc : acc + next), 0)

如果您想保留每个值并仍然检查总和,那么别无选择,只能将每个序列存储在数组中:

let other$ =
    obs$
        .scan((acc, next) => {
            let sum = acc.reduce((a,b)=>a+b);
            if((sum+next)<0){
                return acc; // less than zero, return current arrray
            }
            return  acc.push(next); //greater or equal to zero, add current item to array
        }, [...0])
        .switchMap(array => Observable.from(array))

答案 1 :(得分:0)

基于@CozyAzure的想法,我找到了一个更好的答案。我只需要在reducer中存储更多状态:原始值,累积的总计以及是否将此值添加到总计中。

 让其他$ = obs $
  .scan(({{value,total,valid},next)=> {
     如果(总计+下一个<0)
       返回{值:下一个,总计:总计,有效:假}
     其他
       返回{值:下一个,总计:总计+下一个,有效:true}
  },{值:未定义,总计:0,有效:假})
  .filter(x => x.valid)
  .map(x => x.value)
 

这样,我可以过滤掉未添加 的值,并取回原来的值。