I have a tree structure like this:
const tree = [
{
slug: 'item-1',
children: [
{
slug: 'item-1-1',
children: [
{ slug: 'item-1-1-1' },
{ slug: 'item-1-1-2' }
],
},
],
},
{
slug: 'item-2',
children: [
{
slug: 'item-2-1',
children: [
{ slug: 'item-2-1-1' },
{ slug: 'item-2-1-2' }
],
},
],
},
];
I want to filter it based on the slug
which is not hard. I've seen some recursive solutions on StackOverflow. But I want only the direct children of the item to be in the result. For example, if I search for slug === "item-1"
, the result should be:
[
{
slug: "item-1"
children: [
slug: "item-1-1"
],
},
]
Maybe I can combine filter()
and reduce()
or even map()
and somehow solve this but it doesn't seem optimal. The tree is likely to be big and complex. How would you solve this?
CodePudding user response:
Here's a recursive approach. Basically, we are doing a breadth-first search, firstly we search at a level, and if the required item is found return the result after modifying the children array. If the key is not found in that level search the children.
const tree = [
{
slug: 'item-1',
children: [
{
slug: 'item-1-1',
children: [{ slug: 'item-1-1-1' }, { slug: 'item-1-1-2' }],
},
],
},
{
slug: 'item-2',
children: [
{
slug: 'item-2-1',
children: [{ slug: 'item-2-1-1' }, { slug: 'item-2-1-2' }],
},
],
},
];
const search = (data, key) => {
if (!data?.length) return null;
const children = [];
let found = null;
data.forEach((obj) => {
if (obj.slug === key) {
found = obj;
}
children.push(...(obj.children || []));
});
return found
? {
slug: key,
...(found.children?.length && {
children: found.children.map(({ slug }) => ({ slug })),
}),
}
: search(children, key);
};
console.log(search(tree, 'item-1-1'));