Recursively filter array of objects

后端 未结 7 850
一个人的身影
一个人的身影 2020-11-29 00:00

Hitting a wall with this one, thought I would post it here in case some kind soul has come across a similar one. I have some data that looks something like this:

<         


        
相关标签:
7条回答
  • 2020-11-29 00:34

    Using .filter() and making a recursive call as I described in the comment above is basically what you need. You just need to update each .children property with the result of the recursive call before returning.

    The return value is just the .length of the resulting .children collection, so if there's at least one, the object is kept.

    var res = input.filter(function f(o) {
      if (o.value.includes("Hit")) return true
    
      if (o.children) {
        return (o.children = o.children.filter(f)).length
      }
    })
    

    const input = [
      {
        value: 'Miss1',
        children: [
          { value: 'Miss2' },
          { value: 'Hit1', children: [ { value: 'Miss3' } ] }
        ]
      },
      {
        value: 'Miss4',
        children: [
          { value: 'Miss5' },
          { value: 'Miss6', children: [ { value: 'Hit2' } ] }
        ]
      },
      {
        value: 'Miss7',
        children: [
          { value: 'Miss8' },
          { value: 'Miss9', children: [ { value: 'Miss10' } ] }
        ]
      },
      {
        value: 'Hit3',
        children: [
          { value: 'Miss11' },
          { value: 'Miss12', children: [ { value: 'Miss13' } ] }
        ]
      },
      {
        value: 'Miss14',
        children: [
          { value: 'Hit4' },
          { value: 'Miss15', children: [ { value: 'Miss16' } ] }
        ]
      },
    ];
    
    var res = input.filter(function f(o) {
      if (o.value.includes("Hit")) return true
    
      if (o.children) {
        return (o.children = o.children.filter(f)).length
      }
    })
    console.log(JSON.stringify(res, null, 2))


    Note that .includes() on a String is ES7, so may need to be patched for legacy browsers. You can use the traditional .indexOf("Hit") != -1 in its place.


    To not mutate the original, create a map function that copies an object and use that before the filter.

    function copy(o) {
      return Object.assign({}, o)
    }
    
    var res = input.map(copy).filter(function f(o) {
      if (o.value.includes("Hit")) return true
    
      if (o.children) {
        return (o.children = o.children.map(copy).filter(f)).length
      }
    })
    

    To really squeeze the code down, you could do this:

    var res = input.filter(function f(o) {
      return o.value.includes("Hit") ||
             o.children && (o.children = o.children.filter(f)).length
    })
    

    Though it gets a little hard to read.

    0 讨论(0)
提交回复
热议问题