Home > Blockchain >  how to get an updated copy of a node tree after removing some of its nodes?
how to get an updated copy of a node tree after removing some of its nodes?

Time:05-10

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.

  • Related