Recursively filter array of objects

后端 未结 7 849
一个人的身影
一个人的身影 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:14

    I think it will be a recursive solution. Here is one that I tried.

    function find(obj, key) {
      if (obj.value && obj.value.indexOf(key) > -1){
        return true;
      }
      if (obj.children && obj.children.length > 0){
        return obj.children.reduce(function(obj1, obj2){
          return find(obj1, key) || find(obj2, key);
        }, {}); 
      } 
      return false;
    }
    
    var output = input.filter(function(obj){
         return find(obj, 'Hit');
     });
    console.log('Result', output);
    
    0 讨论(0)
  • 2020-11-29 00:15

    Here is a good solution which utilizes the array reduce function which results in more readable code then the other solutions. Also it is more readable in my opinion. We are calling the filter function recursively to filter an array along with its children

    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" }] },
        ],
      },
    ];
    
    function recursiveFilter(arr) {
      return arr.reduce(function filter(prev, item) {
        if (item.value.includes("Hit")) {
          if (item.children && item.children.length > 0) {
            return prev.concat({
              ...item,
              children: item.children.reduce(filter, []),
            });
          } else {
            return item;
          }
        }
        return prev;
      }, []);
    }
    
    console.log(recursiveFilter(input));

    0 讨论(0)
  • 2020-11-29 00:19

    Alternatively you can use _.filterDeep method from deepdash extension for lodash:

    var keyword = 'Hit';
    var foundHit = _.filterDeep(
      input,
      function(value) {
        return value.value.includes(keyword);
      },
      {
        tree: true,
        onTrue: { skipChildren: true },
      }
    );
    

    Here is a full test for your case

    0 讨论(0)
  • 2020-11-29 00:28

    Array.prototype.flatMap is a good fit for recursive filtering. Similar to map, filter and reduce, using flatMap does not modify the original input -

    const findHits = (t = []) =>
      t.flatMap(({ value, children }) => {
        if (value.startsWith("Hit"))
          return [{ value, children }]
        else {
          const r = findHits(children)
          return r.length ? [{ value, children: r }] : []
        }
      })
    
    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'}]}]}]
    
    const result =
      findHits(input)
    
    console.log(JSON.stringify(result, null, 2))

    [
      {
        "value": "Miss1",
        "children": [
          {
            "value": "Hit1",
            "children": [
              {
                "value": "Miss3"
              }
            ]
          }
        ]
      },
      {
        "value": "Miss4",
        "children": [
          {
            "value": "Miss6",
            "children": [
              {
                "value": "Hit2"
              }
            ]
          }
        ]
      },
      {
        "value": "Hit3",
        "children": [
          {
            "value": "Miss11"
          },
          {
            "value": "Miss12",
            "children": [
              {
                "value": "Miss13"
              }
            ]
          }
        ]
      },
      {
        "value": "Miss14",
        "children": [
          {
            "value": "Hit4"
          }
        ]
      }
    ]
    
    0 讨论(0)
  • 2020-11-29 00:29

    const input = [
      {
        value: 'Miss1',
        children: [
          { value: 'Miss1' },
          { 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: 'Miss14asds',
        children: [
          { value: 'Hit4sdas' },
          { value: 'Miss15', children: [ { value: 'Miss16' } ] }
        ]
      },
    ];
    
    function filter(arr, term) {
        var matches = [];
        
        if (!Array.isArray(arr)) return matches;
    
        arr.forEach(function(i) {
         
            if (i.value === term) {
        
             const filterData =  (i.children && Array.isArray(i.children))? i.children.filter(values => values.value ===term):[];
             console.log(filterData)
             i.children =filterData;
                matches.push(i);
              
            } else {
           // console.log(i.children)
                let childResults = filter(i.children, term);
                if (childResults.length)
         matches.push(Object.assign({}, i, { children: childResults }));
            }
        })
    
        return matches;
    }
    
    
    const filterData= filter(input,'Miss1');
    console.log(filterData)

    Below code for filter the parent and child array data using recursive function

    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))

    0 讨论(0)
  • 2020-11-29 00:30

    Here's a function that'll do what you're looking for. Essentially it will test every item in arr for a match, then recursively call filter on its children. Also Object.assign is used so that the underlying object isn't changed.

    function filter(arr, term) {
        var matches = [];
        if (!Array.isArray(arr)) return matches;
    
        arr.forEach(function(i) {
            if (i.value.includes(term)) {
                matches.push(i);
            } else {
                let childResults = filter(i.children, term);
                if (childResults.length)
                    matches.push(Object.assign({}, i, { children: childResults }));
            }
        })
    
        return matches;
    }
    
    0 讨论(0)
提交回复
热议问题