Search code examples
javascriptjqueryrecursionarray-merge

Recursive Function In JavaScript for array of objects with different keys


Need a recursive function  in javascript/jquery for below json object.

The key "impacted" is the leaf node at each level.

The  key "child" may have any number of levels which may have "impacted" nodes in it.

i want to merge the leaf nodes("impacted") at every level to child("child") node at the same level.

 It means child node at any level should have impacted data also at same level.

Input

{

    "Data": [{
        "id": 1745,
        "name": "Top Parent",
        "parentId": null,
        "child": [{
            "id": 1746,
            "name": "Sub Parent- child to Top Parent",
            "parentId": 1745,
            "child": [{
                    "id": 1747,
                    "name": "child to Sub Parent--One ",
                    "parentId": 1746
                },
                {
                    "id": 1748,
                    "name": "child to Sub Parent--two",
                    "parentId": 1746,
                    "child": [{
                        "id": 1749,
                        "name": "Child to two",    
                        "parentId": 1748
                    }],
                    "impacted": [{
                        "id": 2471,
                        "name": "Leaf of two ",
                        "network": true
                    }]
                }
            ],
            "impacted": [{
                    "id": 2470,
                    "name": "Leaf of Sub Parent-1 ",
                    "network": true
                },
                {
                    "id": 2469,
                    "name": "Leaf of Sub Parent-1",
                    "network": true
                }    
            ]    
        }],    
        "impacted": [{    
            "id": 2468,    
            "name": "Leaf Of Top Parent",    
            "network": true    
        }]    
    }]    
}

Expected Output

{    
    "Data": [{    
        "id": 1745,    
        "name": "Top Parent",    
        "parentId": null,    
        "child": [{    
                "id": 1746,    
                "name": "Sub Parent- child to Top Parent",    
                "parentId": 1745,    
                "child": [{    
                        "id": 1747,    
                        "name": "child to Sub Parent--One ",    
                        "parentId": 1746    
                    },    
                    {    
                        "id": 1748,    
                        "name": "child to Sub Parent--two",    
                        "parentId": 1746,   
                        "child": [{    
                                "id": 1749,    
                                "name": "Child to two",    
                                "parentId": 1748    
                            },      
                            {    
                                "id": 2471,    
                                "name": "Leaf of two ",    
                                "network": true    
                            }    
                        ]    
                    },    
                    {    
                        "id": 2470,    
                        "name": "Leaf of Sub Parent-1 ",    
                        "network": true    
                    },    
                    {    
                        "id": 2469,    
                        "name": "Leaf of Sub Parent-1",    
                        "network": true    
                    }    
                ]    
            },    
            {        
                "id": 2468,    
                "name": "Leaf Of Top Parent",    
                "network": true    
            }    
        ]    
    }]    
}

It is OK even if we do not remove "impacted" key from object. But the data from "impacted" should be merged to "child" of same level.

I tried with following function..but getting duplicates at each level

 

repeatLoop(data){    
    if(data && data.length){    
        for(var i=0;i<data.length;i++){    
       if(data[i].child && data[i].child.length && data[i].impacted && data[i].impacted.length){    
                for(var k=0; k<data[i].impacted.length;k++){    
                     data[i].child.push(data[i].impacted[k])    
                     this.repeatLoop(data[i].child)    
                }    
         }    
       }    
     }    
       return data    
  }

Thanks in advance


Solution

  • The main issue with your code is that you call the function recursively inside a loop on k, while the recursive call does not depend on k at all, so it should not be called in that inner loop, but after it.

    You could use this function:

    class X {
        repeatLoop(data) {
            if (!Array.isArray(data)) return;
            for (var item of data) {
                this.repeatLoop(item.child);
                if (item.impacted) {
                    item.child = (item.child || []).concat(item.impacted);
                    delete item.impacted;
                }
            }
        }
    }
    
    // Sample input
    var data = {
        "Data": [{
            "id": 1745,
            "name": "Top Parent",
            "parentId": null,
            "child": [{
                "id": 1746,
                "name": "Sub Parent- child to Top Parent",
                "parentId": 1745,
                "child": [{
                        "id": 1747,
                        "name": "child to Sub Parent--One ",
                        "parentId": 1746
                    },
                    {
                        "id": 1748,
                        "name": "child to Sub Parent--two",
                        "parentId": 1746,
                        "child": [{
                            "id": 1749,
                            "name": "Child to two",    
                            "parentId": 1748
                        }],
                        "impacted": [{
                            "id": 2471,
                            "name": "Leaf of two ",
                            "network": true
                        }]
                    }
                ],
                "impacted": [{
                        "id": 2470,
                        "name": "Leaf of Sub Parent-1 ",
                        "network": true
                    },
                    {
                        "id": 2469,
                        "name": "Leaf of Sub Parent-1",
                        "network": true
                    }    
                ]    
            }],    
            "impacted": [{    
                "id": 2468,    
                "name": "Leaf Of Top Parent",    
                "network": true    
            }]    
        }]    
    }; 
    // Call function
    new X().repeatLoop(data.Data);
    // Display mutated data:
    console.log(data);
    .as-console-wrapper { max-height: 100% !important; top: 0; }