用可观察的条件过滤观察到的阵列

时间:2020-08-22 17:27:47

标签: javascript angular typescript rxjs

我有一个请求,该请求返回一个对象数组。每个对象都包含一个ID,我可以通过该ID发送另一个请求。基于此结果,我想过滤数组。简化示例:

function getAllObjects(): Observable<{ id: number }[]> {
  return of([
    { id: 1 },
    { id: 2 },
    { id: 3 },
    { id: 4 },
  ]);
}

function checkObject(obj): Observable<boolean> {
  return of(obj.id % 2 === 0);
}

getAllObjects().pipe(
  // TODO
).subscribe(console.log); // I only want to see objects here which passed the async check

4 个答案:

答案 0 :(得分:1)

对您有用吗?

getAllObjects().pipe(
  flatMap((ar) => ar),
  concatMap((obj) => combineLatest([of(obj), checkObject(obj)])),
  filter(([_, checkResult]) => checkResult),
  map(([obj]) => obj),
  toArray(),
).subscribe(console.log);

编辑,我看到您已经找到了解决方案,我的要简单得多,并且我认为您需要一个对象流,而不是将它们作为数组返回。所以我在Edit中添加了toArray。

答案 1 :(得分:0)

可能不是最简单但也可以使用的解决方案

getAllObjects()
    .pipe(
        switchMap(array =>
            combineLatest(array
                .map(obj =>
                    checkObject(obj)
                        .pipe(
                            distinctUntilChanged(),
                            map(boolean => boolean ? obj : null)
                        )
                )
            )
        ),
        map(array => array.filter(obj => obj))
    )
    .subscribe(console.log);

考虑到实时可能的变化

function getAllObjects(): Observable<{ id: number }[]> {
    return timer(0, 10000)
        .pipe(
            map(() => [
                { id: 1 },
                { id: 2 },
                { id: 3 },
                { id: 4 },
            ])
        );
}

function checkObject(obj): Observable<boolean> {
    return timer(1000, 5000)
        .pipe(
            map(() => obj.id % 2 === 0)
        );
}

答案 2 :(得分:0)

const objects$ = getAllObjects().pipe(concatAll());
const objectValidations$ = objects$.pipe(concatMap(checkObject));

zip(objects$, objectValidations$).pipe(
    filter(([, validated]) => validated),
    map(([obj,]) => obj),
    toArray()
).subscribe(console.log);

更新: 我们可以通过并行化“检查”来改善上述解决方案的性能:

getAllObjects().pipe(
  concatAll(),
  mergeMap(obj => 
    checkObject(obj).pipe(
      map(isValid => isValid? obj : undefined),
      filter(Boolean),
    )
  ),
  toArray()
)

那更好,因为如果我们假设以下checkObject的实现(增加了延迟):

function checkObject(obj) {
  return of(obj.id % 2 === 0).pipe(delay(1000));
}

然后,对于n个对象,先前的解决方案将花费n秒,而更新后的解决方案则需要1秒

答案 3 :(得分:-1)

import { map, filter } from 'rxjs/operators';


map(items => items.filter(item => item.id % 2 === 0)),
filter(items => items && items.length > 0)

首先使用map函数并像平常一样过滤数组。 然后,要确保您不会得到null或空数组,请使用filter函数,如果地图为null或空,则该函数不会调用订阅。

相关问题