rxjs:递归在地图内的可观察发射

问题描述 投票:0回答:1

我试图在rxjs中递归地分组数据,我把头发拉了一下。似乎有很多关于不同用例的好例子,但我似乎无法重构代码以满足我的要求。

我可以推断出的核心问题是,在我的map运算符中,我有一个条件返回,它是一个不可观察的或一个可观察的。有没有办法可以重构来解释这种差异?

理想情况下,此函数会将原始“flat”数组按任意数量的列分组,这些列作为cols参数传入。

每次满足条件时,它将以{key:col_name,elements:[... col_elements]}格式附加到数组,其中元素将是相同格式的另一个元素数组,或者是元素的直接列表。

仅将列分组一次(因此从不要求map中的observable发出)时,以下函数有效。

//group data n times based on passed string[] of column attributes
  group_data(elements: Observable<any>, cols: string[], index=0) : Observable<any> {
    let col = cols[index]

    return elements.pipe(
      //groupby column value
      RxOp.groupBy((el:any) => this.get_groupingValue(el, col)),

      //place key inside array
      RxOp.mergeMap((group) => group.pipe(
        RxOp.reduce((acc, cur) => [...acc, cur], ["" + group.key]))
      ),
      // map to key:group
      RxOp.map((arr:any) =>

          cols.length <= index + 1?
          // no more grouping req
          { 'key': arr[0], 'elements': arr.slice(1) } :

          //group recursively, returns Observable instead of array:(
          { 'key': arr[0], 'elements':
            this.group_data(from(arr.slice(1)), cols, index + 1)
              .pipe(
                RxOp.tap(t=> console.log(t)), // not logged
                RxOp.reduce((acc, val) => [...acc, val], [])

              )
          }),
      RxOp.toArray()
    )
  }

//simplified data example:

data = [{id: 'idA', type: 'project', parents: null },
 {id: 'idB', type: 'project', parents: null },
 {id: 'idC', type: 'episode', parents: ['idA'] },
 {id: 'idD', type: 'episode', parents: ['idB'] },
 {id: 'idE', type: 'scene', parents: ['idA', 'idC'] },
 {id: 'idF', type: 'scene', parents: ['idB', 'idD'] }] 

// 1 column passed works correctly as below

group_data(elements: from(data), ['project'])

/* outputted data:
[{key: 'idA', 
  elements: [ {id: 'idC', type: 'episode', parents: ['idA'] },
              {id: 'idE', type: 'scene', parents: ['idA', 'idC'] }]},
{key: 'idB', 
  elements: [ {id: 'idD', type: 'episode', parents: ['idA'] },
              {id: 'idF', type: 'scene', parents: ['idA', 'idC'] }]},

{key: null,
  elements: [ {id: 'idA', type: 'project', parents: [] }
              {id: 'idB', type: 'project', parents: [] }]}
]
*/

// 2 columns not working correctly
group_data(elements: from(data), ['project', 'episode'])
/*[{key: 'idA', 
  elements: Observable},
{key: 'idB', 
  elements: Observable},
{key: null, 
  elements: Observable}
]*/
javascript observable rxjs6
1个回答
0
投票

我需要采取的方法是重构,以便我可以使用mergeMap而不是map - 这意味着我需要两个可观察的条件而不是一个。从那里我只需要重构,以便映射到键,元素是在mergeMap之后完成的。

这仍然是我第一次涉足rxjs,所以我的解释并不是很好,我对这个问题的总结也不是很好。重要的是,至少它现在表现得如预期的那样。

//group data n times based on passed string[] of column attributes
  group_data(elements: Observable<any>, cols: string[], index=0) : Observable<any> {
    let col = cols[index]

    let grouping = elements.pipe(
      //groupby column value
      RxOp.groupBy((el:any) => this.get_groupingValue(el, col)),

      //place key inside array
      RxOp.mergeMap((group) => group.pipe(
        RxOp.reduce((acc, cur) => [...acc, cur], ["" + group.key]))
      )
    )


    return grouping.pipe(
      RxOp.mergeMap((arr) =>
        (
        cols.length <= (index +1) ?

        //no more grouping required
        of(arr.slice(1)) : 

        //group again
        this.group_data(from(arr.slice(1)), cols, index + 1))

        // reduce result and put the key back in
        .pipe(
          RxOp.reduce((acc, cur) => [...acc, cur], ["" + arr[0]])
        )
      ),

      // map to key:group
      RxOp.map(arr => ({
          key: arr[0],
          elements: arr.slice(1)
        })
      ),
      RxOp.toArray()
    )
© www.soinside.com 2019 - 2024. All rights reserved.