Skip to content
Advertisement

How to filter array of nested objects with unknown depth based on given search term

There are similar answers here but all of the ones I’ve seen and tested don’t go pass two levels deep, so I don’t think this is a duplicate problem…I am trying to filter an array of objects. Each of its objects can have other nested objects of unknown depth. For my data, treeView is a collection of treeData, and treeNode(children) will have the same interface.

export interface TreeView = TreeData[]

export interface TreeData {
    label: string;
    children?: TreeData[]
}
const treeData = 
[
  {label: 'obj-1', children: [ {label: 'bananas'},{label: 'apples', children: [
       {label: 'bananas',},{label: 'apples'}, {label: 'coconut',  children: [
           {label: 'bananas'},{label: 'oranges',  },
]},
]}]},
  
{label: 'obj-2', children: [ {label: 'apples'},{label: 'apples', children: [
       {label: 'oranges',},{label: 'apples'}, {label: 'coconut',  children: [
           {label: 'bananas'},{label: 'oranges', children: [
             {label: 'bananas'},{label: 'oranges',  },
] },
]},
]}]},

  {label: 'obj-3', children: [ {label: 'apples'},{label: 'mango'},{label: 'apples', children: [
       {label: 'oranges',},{label: 'apples'}, {label: 'coconut',  children: [
           {label: 'bananas'},{label: 'oranges', children: [
             {label: 'bananas'},{label: 'mango',  },
] },
]},
]}]},
]

Objects with a label that don’t match the searchTerm should be removed, and if an object has a children property, repeat the process. I’ve been trying to solve this with recursion. Here’s my code…

const recurse = (array, searchTerm) => {
  return array.map((element) => {
  return {...element, subElements: element.subElements.filter((subElement) => subElement.label === searchTerm)}
})
}

const filterArray = (myArray,value) => {
  for(let i = 0; i < myArray.length;i++){
    if(myArray.children){
      if(myArray[i].children){
          filterArray(myArray[i].children,value) 
        }
    }
    } 
     recurse(myArray,value)
  }


console.log(filterArray(treeData,'bananas'))

In the example above, searching ‘bananas’ would filter the entire array as many level deep as necessary, removing any objects whose label prop does not equal bananas; if an object does not have children, is its label prop equal to the search term, if not remove it from its parent array. Thanks so much in advance!

I want to return the filtered version of the original array.Only objects with ‘bananas’ as their label should show hereOnly objects with bananas in the entire array should show here

Advertisement

Answer

I think you’ll want something like this:

const filterByLabel = (array, searchTerm) => {
    return array.reduce((prev, curr) => {
        const children = curr.children ? filterByLabel(curr.children, searchTerm) : undefined;
        
        return curr.label === searchTerm || children?.length > 0 ? [...prev, { ...curr, children }] : prev;
    }, []);
}

filterByLabel(treeData, 'bananas');
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement