I'm writing a recursive function on a JSON tree {name, type, [children]} to remove nodes of a certain type. However, the children of the removed node should get re-attached to the parent, if they are not of the type to be removed.
I'm experiencing the following difficulty: Let's say I want to remove type b on the following tree:
const sampleData = [{
name: "parent",
type: "a",
children: [{
name: "childA",
type: "a",
children: null
},{
name: "childB",
type: "b",
children: [{
name: "grandChildA",
type: "a",
children: null
},{
name: "grandChildB",
type: "a",
children: null
}]
},{
name: "childC",
type: "a",
children: null
}]
}]
The original children for parent is [childA, childB, childC].
After the removal, the parent should have children [childA, grandChildA, grandChildB, childC].
However, the result I'm getting is [childA, [grandChildA, grandChildB], childC].
I know I need to spread it out, but I'm not sure where to do it in the recusion.
Here's the function that I have right now (I know I'm using the spread syntax in the wrong place):
const removeType = (node, type) => {
//if the node should not be removed
if (node.type !== type){
//if the node has children, recursively call to prune children
if (node.children && node.children.length > 0){
node.children = [...node.children.map(child => removeType(child, type))
.filter(child => child !== null)]
return node
}
//if the node has no children, return the node
else return node
}
//if the node should be removed
else if (node.type === type){
//if the node has children, recursively call, then reattach the children
if (node.children && node.children.length > 0){
node.children = [...node.children.map(child => removeType(child, type))
.filter(child => child !== null)]
return node.children
}
//
else return null
}
}
Updated
I think you can use reduce for that, I'm not having my computer right now to test it, but it'll be something like this
const removeType = (node, type) => {
if (node === null) {
return null;
} else {
return node.reduce((acc, child) => {
if(child["type"] === type) {
const removedChild = removeType(child["children"], type);
acc = [...acc, ...removedChild];
} else {
child.children = removeType(child["children"], type);
acc.push(child);
}
return acc;
}, []);
}
}
2nd Update
Code reduced:
const removeType = (node, type) => {
if (!node) return;
return node.reduce((acc, child) => {
if(child["type"] === type) {
const removedChild = removeType(child["children"], type);
acc = [...acc, ...removedChild];
} else {
child.children = removeType(child["children"], type);
acc.push(child);
}
return acc;
}, []);
}
I think this answer is just enough different from the others supplied to add it as an alternative. It has the same recursive structure as the answer from Thankyou, but it makes the simplifying assumption that your input is always an array, as are all non-nil children nodes.
const removeType = (node, target) =>
node .flatMap (({type, children, ...rest}) =>
type === target
? children ? removeType (children, target) : []
: [{...rest, type, children: children && (removeType (children, target))}]
)
const sampleData = [{name: "parent", type: "a", children: [{name: "childA", type: "a", children: null},{name: "childB", type: "b", children: [{name: "grandChildA", type: "a", children: null},{name: "grandChildB", type: "a", children: null}]}, {name: "childC", type: "a", children: null}]}]
console .log (
removeType (sampleData, 'b')
)
.as-console-wrapper {min-height: 100% !important; top: 0}
I'm not claiming this as an improvement on the other answers, but it is an interesting alternative.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With