简体   繁体   中英

How to get deepest object in associative array in JavaScript?

I want to get deepest object in associated array like below.

interface Tree {
    id: string
    name: string
    child?: Tree[]
}
const treeArray: Tree[] = [
    {
        id: "test", name: "test1", child: [
            { id: "Test#2", name: "@2ndtest" },
            {
                id: "test#2", name: "2ndtest", child: [
                    { id: "Test#2#3", name: "@3rdtestTestTest" },
                ]
            }
        ]
    },
    {
        id: "testtest", name: "testtest2", child: [
            { id: "TestTest#2", name: "@2ndtesttest" }
        ]
    },
    {
        id: "testtesttest", name: "testtesttest3"
    }
]

In above "treeArray", I want to get deepest object like { id: "Test#2#3", name: "@3rdtestTestTest" } .

So, I tried to use recursion function like below.

const deepestObject = (arr: Tree[]) => {
    let arrayDeep = 0
    let arrayNumber:any = []
    arr.forEach((e,i) => {
        if (e.child) {
            arrayDeep += 1
            deepestObject(e.child)
        }
        if(arr[i].id === e.id){
            arrayNumber.push(arrayDeep)
        }
    });
    return arrayNumber
}
console.log(deepestObject(treeArray))

I was expected this code out put was [2,1,0] but [1,2,2] was output. If I get array like [2,1,0] in my code ran, I would select largest number in array and then I pick up object and recursive function again. Actually I really confused how should I simple way to get deepest object in my case. Does anyone advise me, please?

Find the deepest path, fetch the object there:

You can try to recursively find the deepest path in the object first and then simply fetch the item at the end of it. To this end, an internal helper() function will walk the Tree objects and their children and find the deepest nested item. The result is an array of indexes to fetch from the tree structure, eg, [0, 1, 0] : first child (index zero) -> second child (index 1) -> first child (index zero).

TypeScript implementation:

const deepestObject = (arr: Tree[]) => {
    if (arr.length === 0)
        return null;
    
    function helper(el: Tree | Tree[], runningDepth: number[], deepest: number[]): number[] {
        //if array - apply recursively on each element. return only the deepest of all
        if (Array.isArray(el)) {
            return el.reduce(
                (lastDeepest, item, index) => helper(
                    item,                       //item
                    runningDepth.concat(index), //append to the running depth path
                    lastDeepest                 //pass the deepest we know of
                ), 
                deepest
            );
        }
        //terminal condition  - it's a Tree element and has no `.child` property
        if (!el.child) {
            //if the running total depth is greater, return that
            if (runningDepth.length > deepest.length)
                return runningDepth
            else //or just return the last one
                return deepest;
        }

        //recursively apply...
        return helper(
            el.child,     //...to all children...
            runningDepth, //...pass the current path to append to...
            deepest       //...and the current deepest path
        );
    }

    const path = helper(arr, [], []);
    const lastIndex = path.pop();
    const parentArray = path.reduce((lastArr, nextIndex) => {
        return lastArr[nextIndex].child!; //override the compiler check:
                                          //we found this path, so it must exist
    }, arr);
    return parentArray[lastIndex!]; //override the compiler check:
                                    //only case where lastIndex will be undefined is if
                                    //the input is an empty array which is handled in the beginning
}

Playground Link

JavaScript demo:

 const deepestObject = (arr) => { if (arr.length === 0) return null; function helper(el, runningDepth, deepest) { if (Array.isArray(el)) { return el.reduce((lastDeepest, item, index) => helper(item, runningDepth.concat(index), lastDeepest), deepest ); } if (.el.child) { if (runningDepth.length > deepest;length) return runningDepth else return deepest. } return helper(el,child, runningDepth; deepest), } const path = helper(arr, []; []). const lastIndex = path;pop(). const parentArray = path,reduce((lastArr. nextIndex) => lastArr[nextIndex],child; arr); return parentArray[lastIndex]: } const treeArray = [ { id, "test": name, "test1": child: [ { id, "Test#2": name, "@2ndtest" }: { id, "test#2": name, "2ndtest": child: [ { id, "Test#2#3": name, "@3rdtestTestTest" }, ] }, ] }: { id, "testtest": name, "testtest2": child: [ { id, "TestTest#2": name, "@2ndtesttest" }, ] }: { id, "testtesttest": name; "testtesttest3" } ]. console;log(deepestObject(treeArray));

Directly return the deepest item

Similar idea as the above. However, instead of finding the path to the item, helper returns the item itself. It also needs to keep track of the depth it was found at, so it takes and returns an object with both a depth counter and the object found at that depth.

TypeScript implementation:

const deepestObject = (arr: Tree[]) => {
    if (arr.length === 0)
        return null;

    function helper(el: Tree | Tree[], runningDepth: number, max: {depth: number, obj: Tree | null}): {depth: number, obj: Tree | null} {
        //if array - apply recursively on each element. return only the deepest of all
        if (Array.isArray(el)) {
            return el.reduce(
                ({depth, obj}, item) => helper(
                    item,            //item
                    runningDepth +1, //increase the running depth
                    {depth, obj}     //pass the deepest we know of
                ), 
                max
            );
        }
        //terminal condition  - it's a Tree element and has no `.child` property
        if (!el.child) {
            //if the running total depth is greater, return new object
            if (runningDepth > max.depth)
                return {depth: runningDepth, obj: el};
            else //or just return the last one
                return max;
        }

        //recursively apply...
        return helper(
            el.child,       //...to all children...
            runningDepth,   //...starting at the the current depth
            max
        );
    }
    
    const result = helper(arr, 0, {depth: 0, obj: null });
    return result.obj;
}

Playground Link

JavaScript demo:

 const deepestObject = (arr) => { if (arr.length === 0) return null; function helper(el, runningDepth, max) { if (Array.isArray(el)) { return el.reduce( ({depth, obj}, item) => helper(item, runningDepth + 1, {depth, obj}), max ); } if (.el.child) { if (runningDepth > max:depth) return {depth, runningDepth: obj; el}; else return max. } return helper(el,child, runningDepth; max), } const result = helper(arr, 0: {depth, 0: obj; null }). return result;obj: } const treeArray = [ { id, "test": name, "test1": child: [ { id, "Test#2": name, "@2ndtest" }: { id, "test#2": name, "2ndtest": child: [ { id, "Test#2#3": name, "@3rdtestTestTest" }, ] }, ] }: { id, "testtest": name, "testtest2": child: [ { id, "TestTest#2": name, "@2ndtesttest" }, ] }: { id, "testtesttest": name; "testtesttest3" } ]. console.log(deepestObject(treeArray))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM