网站搜索

angular - 在传递过滤值的同时更新扫描累加器


我正在尝试使用scan来维护一个数据数组并进行一些过滤。

someObservable$.pipe(
   filter(initial=> initial.length !== 0),
   scan((acc, curr) => curr.filter(x => !acc.includes(x))),
   map(data => etc...)
)

我想更新 acc 的值,使其以某种方式保持一个包含所有已处理数据的完整列表,但只将过滤后的值输出到 map。因此,如果第一个通过的列表是 [1,2,3],第二组是 [2,3,4],第一次处理时我希望 data 为 [1,2,3],同时 acc=[1,2,3],第二次处理时 data 为 [4],但 acc=[1,2,3,4]

我是在以一种笨拙的方式处理这件事吗?我感觉可能有更好的方法。

答案#1

我会在 scan 函数中使用 Set 类作为累加器

我查阅了 rxjs 文档寻找任何内置的替代方案,但找不到适合这种情况的。

请看看这个例子。

var subject = new rxjs.Subject();

const obs = subject.pipe(
  rxjs.operators.scan((acc, current) => {current.map(pr => acc.add(pr)); return acc;}, new Set()) // 1 solution
  //rxjs.operators.scan((acc, current) => [...new Set([...acc, ...current])]) // 2 solution
  //rxjs.operators.scan((acc, current) => [...acc, ...current.filter(pr => !acc.includes(pr))]) // 3 solution - if you cant use Set
  //rxjs.operators.scan((acc, current) => acc.concat(current.filter(pr => !acc.includes(pr)))) // 4 solution - if you cant use Set and spread
);

const subscription = obs.subscribe(val => {
  console.log([...val]);
});

subject.next([1,2,3]);
subject.next([2,3,4]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>

答案#2

如果我猜对了你的意图,下面的代码应该就足够了:

static acc = new Set<number>();
...
return someObservable$.pipe(
  map( list => {
    let res = [];
    list.forEach( e => {
      if ( !acc.has( e ) ) {
        acc.set( e );
        res.push( e );
      }
    } );
    return res;
  } ),
  filter( list => list.length > 0 )
);