Here is my sample object, suppose If I give the child id "services/bsf/diamSetting" it should return a string like so "nf-bsf -> bsfConfig -> services/bsf/diamSetting"
let arr = [{
"attr": {
"id": "nf-bsf",
"name": "BSF",
"sequence": 1
},
"children": [{
"attr": {
"id": "bsfGeneralConfig",
"name": "General Configurations",
"sequence": 10
},
"children": [{
"attr": {
"id": "services/bsf/bsfGlobalCfg",
"name": "General Settings",
"topic": "bsf.global.cfg",
"sequence": 10
}
}, {
"attr": {
"id": "configurations/bsf/sbiErrorCodes",
"name": "SBI Error Codes",
"topic": "bsf.sbi.errorcodes",
"sequence": 20
}
}]
}, {
"attr": {
"id": "services/bsf/conLoggingLevel",
"name": "Logging Level",
"topic": "consistent.logging.cfg.topics",
"sequence": 20
}
}, {
"attr": {
"id": "bsfServices",
"name": "Service Configurations",
"sequence": 30
},
"children": [{
"attr": {
"id": "services/bsf/managementService",
"name": "Management Service",
"topic": "bsf.managementservice",
"sequence": 10
}
}]
}, {
"attr": {
"id": "bsfConfig",
"name": "Diameter Configurations",
"sequence": 40
},
"children": [{
"attr": {
"id": "services/bsf/diamSetting",
"name": "Settings",
"topic": "common.diamsetting",
"sequence": 10
}
}, {
"attr": {
"id": "configurations/bsf/diamPeerNode",
"name": "Peer Nodes",
"topic": "common.public.diampeernode",
"sequence": 20
}
}, {
"attr": {
"id": "services/bsf/diamRoutingTable",
"name": "Routing Table",
"topic": "common.public.diamroutingtable",
"sequence": 30
}
}, {
"attr": {
"id": "configurations/bsf/diamLoadShedding",
"name": "Load Shedding Profiles",
"topic": "common.public.diamloadshedding",
"sequence": 40
}
}, {
"attr": {
"id": "configurations/bsf/diamMessagePriority",
"name": "Message Priority Profiles",
"topic": "common.public.diammessagepriority",
"sequence": 50
}
}]
}, {
"attr": {
"id": "bsf-sessionViewer",
"name": "Session Viewer",
"sequence": 50
}
}, {
"attr": {
"id": "administration",
"name": "Administration",
"sequence": 60
},
"children": [{
"attr": {
"id": "bsfBulkExportImport",
"name": "Export & Import",
"sequence": 10
}
}]
}]
}];
I have tried the following to traverse, i either get undefined or some wrong path. i don't even get child node with this, and this will be traversed in a reverse order.
var parent = [];
const findParent = (arr, id) => {
for (let i=0; i<arr.length; i++) {
if(arr[i].attr.id == id) {
return parent;
} else if (arr[i].children && arr[i].children.length) {
parent.push(arr[i].attr.id);
findParent(arr[i].children, id)
}
}
};
let x = findParent(arr, "services/bsf/diamSetting");
console.log(x)
Your parent
array breaks function encapsulation, creating multiple issues:
parent
may have stale information from a previous traversal. Here's an approach that addresses these problems. I'm using a closure to keep the result array scoped locally to its function, pop
to undo every push
that didn't wind up leading to the target, and some
to bail out from the search and start unwinding the call stack as soon as the target is found.
const tree = [ { "attr": { "id": "nf-bsf", "name": "BSF", "sequence": 1 }, "children": [ { "attr": { "id": "bsfGeneralConfig", "name": "General Configurations", "sequence": 10 }, "children": [ { "attr": { "id": "services/bsf/bsfGlobalCfg", "name": "General Settings", "topic": "bsf.global.cfg", "sequence": 10 } }, { "attr": { "id": "configurations/bsf/sbiErrorCodes", "name": "SBI Error Codes", "topic": "bsf.sbi.errorcodes", "sequence": 20 } } ] }, { "attr": { "id": "services/bsf/conLoggingLevel", "name": "Logging Level", "topic": "consistent.logging.cfg.topics", "sequence": 20 } }, { "attr": { "id": "bsfServices", "name": "Service Configurations", "sequence": 30 }, "children": [ { "attr": { "id": "services/bsf/managementService", "name": "Management Service", "topic": "bsf.managementservice", "sequence": 10 } } ] }, { "attr": { "id": "bsfConfig", "name": "Diameter Configurations", "sequence": 40 }, "children": [ { "attr": { "id": "services/bsf/diamSetting", "name": "Settings", "topic": "common.diamsetting", "sequence": 10 } }, { "attr": { "id": "configurations/bsf/diamPeerNode", "name": "Peer Nodes", "topic": "common.public.diampeernode", "sequence": 20 } }, { "attr": { "id": "services/bsf/diamRoutingTable", "name": "Routing Table", "topic": "common.public.diamroutingtable", "sequence": 30 } }, { "attr": { "id": "configurations/bsf/diamLoadShedding", "name": "Load Shedding Profiles", "topic": "common.public.diamloadshedding", "sequence": 40 } }, { "attr": { "id": "configurations/bsf/diamMessagePriority", "name": "Message Priority Profiles", "topic": "common.public.diammessagepriority", "sequence": 50 } } ] }, { "attr": { "id": "bsf-sessionViewer", "name": "Session Viewer", "sequence": 50 } }, { "attr": { "id": "administration", "name": "Administration", "sequence": 60 }, "children": [ { "attr": { "id": "bsfBulkExportImport", "name": "Export & Import", "sequence": 10 } } ] } ] } ]; const findPath = (children, targetId) => { const path = []; (function search(children) { return children?.some(child => { path.push(child.attr.id); if (child.attr.id === targetId || search(child.children)) { return true; } path.pop(); }); })(children); return path; }; const path = findPath(tree, "services/bsf/diamSetting"); console.log(path.join(" -> "));
Using a parent
variable outside of the function will break the recursion because each level of recursion shares a common varaible, meaning result of one recursion may overwrite the previous result of another recursion.
You should instead make the parent
variable something private to the findParent
function itself so that each recursion will create its own array and modify/returns it.
Here's a revised code that make use of a third argument hierarchy
that functions the same as your parent
, but private to each function call ( closure ):
const arr = [ { "attr": { "id": "nf-bsf", "name": "BSF", "sequence": 1 }, "children": [ { "attr": { "id": "bsfGeneralConfig", "name": "General Configurations", "sequence": 10 }, "children": [ { "attr": { "id": "services/bsf/bsfGlobalCfg", "name": "General Settings", "topic": "bsf.global.cfg", "sequence": 10 } }, { "attr": { "id": "configurations/bsf/sbiErrorCodes", "name": "SBI Error Codes", "topic": "bsf.sbi.errorcodes", "sequence": 20 } } ] }, { "attr": { "id": "services/bsf/conLoggingLevel", "name": "Logging Level", "topic": "consistent.logging.cfg.topics", "sequence": 20 } }, { "attr": { "id": "bsfServices", "name": "Service Configurations", "sequence": 30 }, "children": [ { "attr": { "id": "services/bsf/managementService", "name": "Management Service", "topic": "bsf.managementservice", "sequence": 10 } } ] }, { "attr": { "id": "bsfConfig", "name": "Diameter Configurations", "sequence": 40 }, "children": [ { "attr": { "id": "services/bsf/diamSetting", "name": "Settings", "topic": "common.diamsetting", "sequence": 10 } }, { "attr": { "id": "configurations/bsf/diamPeerNode", "name": "Peer Nodes", "topic": "common.public.diampeernode", "sequence": 20 } }, { "attr": { "id": "services/bsf/diamRoutingTable", "name": "Routing Table", "topic": "common.public.diamroutingtable", "sequence": 30 } }, { "attr": { "id": "configurations/bsf/diamLoadShedding", "name": "Load Shedding Profiles", "topic": "common.public.diamloadshedding", "sequence": 40 } }, { "attr": { "id": "configurations/bsf/diamMessagePriority", "name": "Message Priority Profiles", "topic": "common.public.diammessagepriority", "sequence": 50 } } ] }, { "attr": { "id": "bsf-sessionViewer", "name": "Session Viewer", "sequence": 50 } }, { "attr": { "id": "administration", "name": "Administration", "sequence": 60 }, "children": [ { "attr": { "id": "bsfBulkExportImport", "name": "Export & Import", "sequence": 10 } } ] } ] } ]; const findParent = ( arr, id, hierarchy = [] // Use an array here to store parents instead of using an external variable. ) => { for (let i = 0; i < arr.length; i++){ // If id is found, push it to the result array, stop the loop, then return the result. if (arr[i].attr.id === id){ hierarchy.push(arr[i].attr.id); return hierarchy; } // If id is not found, proceed to its children if (arr[i].children && arr[i].children.length){ const childResult = findParent( arr[i].children, id, [...hierarchy, arr[i].attr.id] // Pass the found parents so far to its child recursion. ); // Only stop the loop and return the result if id is found in child. if (childResult){ return childResult; } } // Proceed to the next loop if id is not found in current item AND its offspring children. } // Return null if id is not found in this branch. return null; }; let x = findParent(arr, "services/bsf/diamSetting"); console.log(x && x.join(' -> '));
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.