将 parent child 结构展平为解析为数组的 BehaviorSubject

Flatten a parent child structure to a BehaviorSubject that resolves to an array

我有一个 BehaviourSubject 解析为一个集合,其中的每个项目都有一个 属性 children,它也是一个 BehaviourSubject 解析为一个项目集合。 现在我想订阅我的主题并将整个内容展平成一个数组,其中每个项目和每个 child.

都有一行

所以符合以下内容:

interface Parent = {
  children: BehaviorSubject<Child[]>
}

现在我想从中创建另一个行为主题,解析为一个数组,其中每个 parent 都有一个项目,后跟 children.

开始于:

const collection: BehaviorSubject<Parent[]>;

想要结果:

const behaviourSubject: BehaviorSubject<(Parent|Child)[]>;

behaviourSubject.subscribe((result: (Parent|Child)[]) => { 
  ...desired result... 
});

所以假设集合中的第一个 Parent 有 3 children,第二个有 2 children 那么如果我订阅结果 behaviourSubject输出应如下所示。

result: [Parent, Child, Child, Child, Parent, Child, Child];

我该如何实现。

我试图通过阅读 RxJS 的文档和检查示例来弄清楚如何做到这一点,但我想最近睡眠不足似乎让我的大脑像干海绵一样工作,我认为最好的方法是正确的现在是在 Whosebug 上寻求帮助。

注意:如果parent集合或children得到一个新值,结果也应该更新...

像下面这样的东西显示了工作,但我想知道你为什么使用 BehaviorSubject 来增加复杂性

import { first, switchMap, toArray, map } from 'rxjs/operators';
import { pipe, BehaviorSubject, from } from 'rxjs';

//...

const parent1={children:new BehaviorSubject([{name:'john'},{name:'may'},{name:'betty'}])}

const parent2={children:new BehaviorSubject([{name:'key'},{name:'tom'}])}

const collection=new BehaviorSubject([parent1,parent2]);

collection.pipe(
  first(),
  switchMap(parent=>from(parent)),
  switchMap(p=>p.children.pipe(first(),map(c=>[p,...c]))),
  toArray(),
  map(arr=>arr.flat())
).subscribe(console.log)

如果您不介意使用 BehaviourSubject 中的 .value 属性,代码可以简化为以下内容

collection.value.map(p=>[p,...p.children.value]).flat()

编辑(通过 OP):

我会为那些想知道这个答案中不同步骤的人编辑这个问题,我把它分成几部分。
也可以在 this StackBlitz 中找到它来玩。

构建数据:

import { first, switchMap, toArray, map } from 'rxjs/operators';
import { pipe, BehaviorSubject, from } from 'rxjs';

class Child {
  constructor(public name: string){
  }
}

class Parent {
  constructor(public children: BehaviorSubject<Child[]>){
  }
}

const collection = new BehaviorSubject([
  new Parent(new BehaviorSubject([
    new Child('john'),
    new Child('may'),
    new Child('betty'),
  ])),
  new Parent(new BehaviorSubject([
    new Child('key'),
    new Child('tom'),
  ])),
]);

这里是最终的可观察对象,它在管道中进行了不同的操作,并添加了注释以解释它们在订阅结果时究竟做了什么:

collection.pipe(
  //Emit the first value 
  first(),
  // Complete previous inner observable, emit values
  switchMap((parents: Parent[]) => { 
    // Emit array as a sequence of values
    return from(parents)
  }),
  // complete previous inner observable, emit values
  switchMap((parent: Parent) => { 
    return parent.children.pipe(
      // Emit the first value 
      first(),
      // Apply projection with each value from source
      map(
        (children: Child[]) => {
          // return desired array for each parent
          return [parent, ...children];
        }
      )
    )
  }),
  //Collects all source emissions and emits them as an array when the source completes
  toArray(),
  //map(arr=>arr.flat())
  map((array: (Parent|Child)[][] ) => {
    // Flatten the array
    return array.flat();
  }),
).subscribe(console.log)