I need based on a condition to remove a node from a tree nodes and obtain as a result an updated copy of the tree nodes
With the help of this answer https://stackoverflow.com/a/72121755/615274 I get to the node to delete, I exclude it from the array it belongs to but the returned node tree does not reflect the changes
The data is as follows
const data = [
{
data: 1,
children: [
{ data: 1000, children: [] },
{ data: 1200, children: [] },
],
},
{
data: 2,
children: [
{
data: 10,
children: [
{ data: 1001, children: [] },
{ data: 1201, children: [] },
{ data: 1002, children: [] },
{
data: 1201,
children: [
{ data: 111, children: [] },
{ data: 222, children: [] },
],
},
],
},
{
data: 12,
children: [
{ data: 100, children: [] },
{ data: 120, children: [] },
],
},
],
},
];
The logic I use now is the following
function deleteNode(treeNode, targetId) {
if (treeNode && Array.isArray(treeNode) && treeNode.length > 0) {
for (let node of treeNode) {
if (node.data === targetId) {
treeNode = treeNode.filter((n) => n.data !== targetId);
break;
}
deleteNode(node.children, targetId);
}
}
return treeNode;
}
This identifies the node to delete, excludes it from it container, but when returning the node tree, the modification is not reflected.
const data = [
{
data: 1,
children: [
{ data: 1000, children: [] },
{ data: 1200, children: [] },
],
},
{
data: 2,
children: [
{
data: 10,
children: [
{ data: 1001, children: [] },
{ data: 1201, children: [] },
{ data: 1002, children: [] },
{
data: 1201,
children: [
{ data: 111, children: [] },
{ data: 222, children: [] },
],
},
],
},
{
data: 12,
children: [
{ data: 100, children: [] },
{ data: 120, children: [] },
],
},
],
},
];
function deleteNode(treeNode, targetId) {
if (treeNode && Array.isArray(treeNode) && treeNode.length > 0) {
for (let node of treeNode) {
if (node.data === targetId) {
treeNode = treeNode.filter((n) => n.data !== targetId);
console.log("==== deleted node ====")
console.dir(treeNode, { depth: null });
console.log("==== deleted node ====")
break;
}
deleteNode(node.children, targetId);
}
}
return treeNode;
}
const output = deleteNode(data, 111);
console.dir(output, { depth: null });
Thanks in advance
CodePudding user response:
The problem was solved in the following way
function deleteNode(nodes, targetId) {
if (nodes && Array.isArray(nodes) && nodes.length > 0) {
nodes.forEach((node, index) => {
if (node.data === targetId) {
nodes.splice(index, 1)
}
deleteNode(node.children, targetId)
});
}
return nodes;
}
The main change is that now when I delete the element I do it using the splice function which modifies the original array. And because objects as arrays are passed to functions as references, every change made inside the function affects the original array.
It can be simplified like this
function deleteNode(nodes, targetId) {
if (nodes && Array.isArray(nodes) && nodes.length > 0) {
nodes.forEach((node, index) => {
if (node.data === targetId) {
nodes.splice(index, 1)
}
deleteNode(node.children, targetId)
});
}
}
CodePudding user response:
I regularly use variants of a deepFilter
function, which lets us build a non-mutating version of this very easily:
const deepFilter = (pred) => (xs) =>
xs .flatMap (({children = [], ...rest}, _, __, kids = deepFilter (pred) (children)) =>
pred (rest) || kids.length
? [{...rest, ...(kids.length ? {children: kids} : {})}]
: []
)
const deleteNode= (target) =>
deepFilter (node => node .data !== target)
const data = [{data: 1, children: [{data: 1e3, children: []}, {data: 1200, children: []}]}, {data: 2, children: [{data: 10, children: [{data: 1001, children: []}, {data: 1201, children: []}, {data: 1002, children: []}, {data: 1201, children: [{data: 111, children: []}, {data: 222, children: []}]}]}, {data: 12, children: [{data: 100, children: []}, {data: 120, children: []}]}]}]
console .log (deleteNode (111) (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
deepFilter
tests a given predicate function against each of your input values, and recursively against their children. If it returns true for the value or for any of its children, we keep that value in the result. If not, we skip it.
That lets us write a trivial deleteNode
function, simply by testing whether the node's data
property is different from our target value.