Skip to content
Advertisement

Derecursing this specific JS function

I wrote the following recursive JS function that takes a single parameter node which is made of other nodes and modifies it by adding to each node its number of leaves (not only direct children) :

const addWidths = (node) => {
    const keys = Object.keys(node)
    for(const key of keys){
        addWidths(node[key])
    }
    if(keys.length > 0){
        node["width"] = Object.values(node).reduce((acc, cur) => acc + cur["width"], 0)
    }else{
        node["width"] = 1
    }
}

Here’s an example of the node parameter :

const object = {
    "A": {
        "1": {},
        "2": {
            "+": {},
            "-": {}
        },
        "3": {}
    },
    "B": {
        "1": {}
    },
    "C": {},
    "D": {}
}

addWidth(object) would modify it and turn it into :

{
    "A": {
        "1": {
            "width": 1
        },
        "2": {
            "+": {
                "width": 1
            },
            "-": {
                "width": 1
            },
            "width": 2
        },
        "3": {
            "width": 1
        },
        "width": 4
    },
    "B": {
        "1": {
            "width": 1
        },
        "width": 1
    },
    "C": {
        "width": 1
    },
    "D": {
        "width": 1
    },
    "width":7
}

I need help to make my function iterative.

EDIT: Here’s a drawing of the modified tree with the expected widths of each node :

enter image description here

Advertisement

Answer

It looks like your intent is to only count leaves in the tree, not internal nodes.

Your recursive implementation can be written without recursion by using an explicit stack to mimic what the recursive implementation does:

const addWidths = (node) => {
    const stack = [[node, Object.values(node)]];
    while (stack.length) {
        const [node, nonvisited] = stack.at(-1);
        if (nonvisited.length == 0) {
            stack.pop();
            node.width = Object.values(node)
                        .reduce((sum, {width}) => sum + width, 0) || 1;
        } else {
            const child = nonvisited.pop();
            stack.push([child, Object.values(child)]);
        }
    }
}

const object = {
    "A": {
        "1": {},
        "2": {
            "+": {},
            "-": {}
        },
        "3": {}
    },
    "B": {
        "1": {}
    },
    "C": {},
    "D": {}
}
addWidths(object);
console.log(object);

Here is a variant that has a more flat stack structure:

const addWidths = (node) => {
    const stack = [node];
    while (stack.length) {
        const node = stack.pop();
        const children = Object.values(node);
        if (children.length && !children[0].width) {
            stack.push(node, ...children);
        } else {
            node.width = children.reduce((sum, {width}) => sum + width, 0) || 1;
        }
    }
}

const object = {
    "A": {
        "1": {},
        "2": {
            "+": {},
            "-": {}
        },
        "3": {}
    },
    "B": {
        "1": {}
    },
    "C": {},
    "D": {}
}
addWidths(object);
console.log(object);
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement