0

I'm trying to figure out an efficient way to change the values of all leaf nodes in a tree structure when said leaf nodes could be at any level. I took a look at these examples:

Looping through nested array of objects

How to find the leaf nodes with recursion in javascript?

Recursively find all children from parent menu

how to change the property value of an object nested in a tree of nodes?

and managed to kludge together something that works for any depth up to a hard coded max. The last link I listed looked so close to what I needed, but I was unable to adapt that code to work with my data structure. Here is what I've got so far:

const data = {
    "name": "Root",
    "children": [{
            "name": "JAN",
            "children": [{
                    "name": "Things1",
                    "value": 2
                },
                {
                    "name": "Things2",
                    "value": 4
                }
            ]
        },
        {
            "name": "Sept",
            "children": [{
                "name": "things3",
                "value": 2
            }]
        },
        {
            "name": "OCT",
            "children": [{
                    "name": "Day1",
                    "value": 5
                },
                {
                    "name": "Month",
                    "children": [{
                            "name": "Day 2",
                            "value": 3
                        },
                        {
                            "name": "Day3",
                            "value": 4
                        },
                        {
                            "name": "Day4",
                            "value": 6
                        },
                        {
                            "name": "Day5",
                            "value": 2
                        },
                        {
                            "name": "Day 6",
                            "value": 5
                        },
                        {
                            "name": "Day7",
                            "value": 2
                        },
                        {
                            "name": "Day 8",
                            "value": 7
                        },
                        {
                            "name": "number 9",
                            "value": 5
                        },
                        {
                            "name": "Stuff",
                            "value": 6
                        },
                        {
                            "name": "Things",
                            "value": 2
                        },
                        {
                            "name": "Moar nonsense",
                            "value": 2
                        },
                        {
                            "name": "Planes fly high",
                            "value": 4
                        },
                        {
                            "name": "Crossfit",
                            "value": 7
                        },
                        {
                            "name": "Anothert",
                            "value": 3
                        },
                        {
                            "name": "Granade",
                            "value": 4
                        },
                        {
                            "name": "Purpose",
                            "value": 2
                        }
                    ]
                },

                {
                    "name": "Week 3",
                    "children": [{
                            "name": "Front",
                            "value": 1
                        },
                        {
                            "name": "Position",
                            "value": 5
                        },
                        {
                            "name": "Operate",
                            "value": 6
                        },
                        {
                            "name": "Back",
                            "value": 4
                        },
                        {
                            "name": "Dragon",
                            "value": 6
                        },
                        {
                            "name": "Ogre",
                            "value": 5
                        }
                    ]
                },
                {
                    "name": "Lair Actions",
                    "children": [{
                            "name": "Use",
                            "value": 1
                        },
                        {
                            "name": "Posion",
                            "value": 5
                        },
                        {
                            "name": "Difficult Terrain",
                            "value": 6
                        },
                        {
                            "name": "Fireball",
                            "value": 4
                        }
                    ]
                },
                {
                    "name": "One Shot",
                    "value": 5
                }
            ]
        }
    ]
}
let messagearry = data.children

function setVals(messagearry) {

    const valueScale = 100;
    //    console.log(messagearry[0])
    // messagearry.forEach(data => {
    //     console.log("testing")
    //     console.log(data.children)
    //     setVals(data.children)
    // })
    let leafnum = 0;

    function findDuplicates(arr) {
        return arr.filter((currentValue, currentIndex) =>
            arr.indexOf(currentValue) !== currentIndex);
    }
    console.log(findDuplicates(data2))

    //below this works but only for 4 levels. If we have more than that it won't work
    Object.keys(messagearry).forEach((key) => {


        const childrenArray = messagearry[key].children;
        Object.keys(childrenArray).forEach((key, index) => {

            if (!isNaN(childrenArray[key].value)) {
                childrenArray[key].value = childrenArray[key].value * valueScale

            }
            console.log("high level " + childrenArray[key].value)
            if (isNaN(childrenArray[key].value)) {
                let whatever = childrenArray[key].children
                whatever.forEach(key => {
                    key.value = key.value * valueScale

                })
            }

        })

    })

}

setVals(messagearry)

There has got to be a better, less rigid way to do this, but I'm really bad at recursion and javascript isn't my best language.

1 Answer 1

1

Assuming that for "leaf" you mean all the objects which have no children, and the children prop is the homonym. And assuming that the tree is an array of same shape's objects (so the children's key is always the same).

The recursion is very easy, just a little tricky.
Basically i do a for which repeats itself for all the children of an object. If it hasn't i just set the value to whatever you decided at the beginning (same for all leaf) and go on with next object of the current array if there's, or quit the function. The property name of the children and the value are parametrized, so it is a little dynamic.

function setLeaf (tree = [], newValue, childLabel, valueLabel) {
    for (const item of tree.values()) {
        if (item[childLabel]?.length) { // optional chaining children doesn't exist or empty array
            setLeaf(item[childLabel], newValue, childLabel, valueLabel);
        } else {
            item[valueLabel] = newValue;
        }
    }
}

setLeaf(data.children, 'LEAF', 'children', 'value');

const data = {
    name: 'Root',
    children: [{
        name: 'JAN',
        children: [{
            name: 'Things1',
            value: 2
        },
        {
            name: 'Things2',
            value: 4
        }
        ]
    },
    {
        name: 'Sept',
        children: [{
            name: 'things3',
            value: 2
        }]
    },
    {
        name: 'OCT',
        children: [{
            name: 'Day1',
            value: 5
        },
        {
            name: 'Month',
            children: [{
                name: 'Day 2',
                value: 3
            },
            {
                name: 'Day3',
                value: 4
            },
            {
                name: 'Day4',
                value: 6
            },
            {
                name: 'Day5',
                value: 2
            },
            {
                name: 'Day 6',
                value: 5
            },
            {
                name: 'Day7',
                value: 2
            },
            {
                name: 'Day 8',
                value: 7
            },
            {
                name: 'number 9',
                value: 5
            },
            {
                name: 'Stuff',
                value: 6
            },
            {
                name: 'Things',
                value: 2
            },
            {
                name: 'Moar nonsense',
                value: 2
            },
            {
                name: 'Planes fly high',
                value: 4
            },
            {
                name: 'Crossfit',
                value: 7
            },
            {
                name: 'Anothert',
                value: 3
            },
            {
                name: 'Granade',
                value: 4
            },
            {
                name: 'Purpose',
                value: 2
            }
            ]
        },

        {
            name: 'Week 3',
            children: [{
                name: 'Front',
                value: 1
            },
            {
                name: 'Position',
                value: 5
            },
            {
                name: 'Operate',
                value: 6
            },
            {
                name: 'Back',
                value: 4
            },
            {
                name: 'Dragon',
                value: 6
            },
            {
                name: 'Ogre',
                value: 5
            }
            ]
        },
        {
            name: 'Lair Actions',
            children: [{
                name: 'Use',
                value: 1
            },
            {
                name: 'Posion',
                value: 5
            },
            {
                name: 'Difficult Terrain',
                value: 6
            },
            {
                name: 'Fireball',
                value: 4
            }
            ]
        },
        {
            name: 'One Shot',
            value: 5
        }
        ]
    }
    ]
};

function setLeaf (tree = [], newValue, childLabel, valueLabel) {
    for (const item of tree.values()) {
        if (item[childLabel]?.length) {
            setLeaf(item[childLabel], newValue, childLabel, valueLabel);
        } else {
            item[valueLabel] = newValue;
        }
    }
}

setLeaf(data.children, 'LEAF', 'children', 'value');

console.log(data);

Sign up to request clarification or add additional context in comments.

1 Comment

That is really awesome! Thanks so much. It makes sense when it's laid out like that. I appreciate the help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.