RxJS 6过滤和映射可观察项目数组

时间:2018-12-06 22:51:34

标签: angular rxjs

在带有RxJS 6.3.3的Angular 7.1.1应用程序中,应将可观察到的计划阵列转换为可观察到的活动计划卡阵列。有效过滤器为:

filter(plan => plan.is_active)

计划从卡转换为:

map(plan => new PlanCard(plan, 1, 1))

所以,大概,答案是这样的:

plans: Observable<Plan[]> = getPlans();

cards: Observable<PlanCard[]> = plans.pipe(
  mergeAll(),
  filter(plan => plan.is_active),
  map(plan => new PlanCard(plan, 1, 1)),
  toArray()
);

但是,{cards是空的。

可以通过以下方式将计划正确转换为卡片:

cards: Observable<PlanCard[]> = plans.pipe(
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1)))
);

但是,不幸的是,事先添加过滤器并不能过滤计划:

cards: Observable<PlanCard[]> = plans.pipe(
  filter(plans => plans.filter(plan => plan.is_active)),
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1)))
);

还有更好的主意吗?

export const planData: Plan[] = [{
  name: 'P1',
  is_active: true
}, {
  name: 'P2',
  is_active: true
}, {
  name: 'P3',
  is_active: true
}, {
  name: 'P4',
  is_active: true
}, {
  name: 'P5',
  is_active: false
}];

export const plans = createObservable(planData);

2 个答案:

答案 0 :(得分:4)

mergeAll合并一个可观察对象。

你想要

cards: Observable<PlanCard[]> = plans.pipe(
  map(plans => plans.filter(plan => plan.is_active)), // An array comes down the pipe, you don't want to filter out the arrays but the elements in the array
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1))), // An array of active plans can be mapped into an array of PlanCards
  reduce((results, plans) => [...results, ...plans], []) // Reduce all the arrays into a single array
);

如果要让reduce的累加器在每次新阵列发生故障时都下降,可以使用scan而不是reduce,仅在所有阵列都下降到管道之后才减少火警。

我通常不使用过滤器,后跟地图,但是更容易看到正在发生的事情,我通常会在一个步骤中通过reduce进行操作,

plans => plans.reduce((results, plan) => plan.is_active ? [...results, new PlanCard(plan, 1, 1)] : results, [])

与后面跟有地图的过滤器相同,但一次迭代而不是两次迭代。

当您拥有数组的可观察对象时,您需要考虑要对观察对象应用哪些函数以及要对管道中的数组应用哪些函数,这可能会造成混乱。

const { from } = rxjs;
const { map, reduce } = rxjs.operators;

const plans = from([
  [{id: 1, is_active: true}, {id: 2, is_active: false}, {id: 3, is_active: true}, {id: 4, is_active: true}],
  [{id: 5, is_active: true}, {id: 6, is_active: true}],
  [{id: 7, is_active: false}, {id: 8, is_active: true}, {id: 9, is_active: true}],
  [{id: 10, is_active: true}, {id: 11, is_active: false}, {id: 12, is_active: true}, {id: 13, is_active: false}],
]);

function PlanCard(plan) {
  this.id = plan.id;
}

plans.pipe(
  map(plans => plans.reduce((results, plan) => plan.is_active ? [...results, new PlanCard(plan, 1, 1)] : results, [])),
  reduce((results, plans) => [...results, ...plans], [])
).subscribe(results => { console.log(results); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.3.3/rxjs.umd.min.js"></script>

答案 1 :(得分:0)

这让我挠了一下头,所以举一个简短的例子,如果您要过滤可观察对象的数组,这可能会有所帮助。感谢@ Adrian指出正确的方向。

如果您有返回可观察对象数组的服务,例如:

dataSub = new BehaviorSubject<Array<object>>([]);

getItems(): Observable<Array<object>>  {
    return this.dataSub.asObservable();
}

您可以使用以下条件过滤给定的条件。在此示例中,我只需要'selected'属性为true的元素。

constructor() {
  this.getItems()
    .pipe(
      map(items => items.     /* Don't forget this! */
      filter(item => item['selected'] === true))
    )
    .subscribe(data => {
      console.log(data);
    });
}

导致我困惑的(菜鸟)错误忽略了“地图”,因此过滤器功能被应用于整个数组,而不是每个元素。