I'm trying to figure out how to search for a node in this JSON object recursively. I have tried something but cannot get it:
var tree = {
"id": 1,
"label": "A",
"child": [
{
"id": 2,
"label": "B",
"child": [
{
"id": 5,
"label": "E",
"child": []
},
{
"id": 6,
"label": "F",
"child": []
},
{
"id": 7,
"label": "G",
"child": []
}
]
},
{
"id": 3,
"label": "C",
"child": []
},
{
"id": 4,
"label": "D",
"child": [
{
"id": 8,
"label": "H",
"child": []
},
{
"id": 9,
"label": "I",
"child": []
}
]
}
]
};
Here is my non-working solution, which is probably because the first node is just a value while children are in arrays:
function scan(id, tree) {
if(tree.id == id) {
return tree.label;
}
if(tree.child == 0) {
return
}
return scan(tree.child);
};
Your code is just missing a loop to inspect each child of a node in the child
array. This recursive function will return the label
property of a node or undefined
if label not present in tree:
const search = (tree, target) => {
if (tree.id === target) {
return tree.label;
}
for (const child of tree.child) {
const found = search(child, target);
if (found) {
return found;
}
}
};
const tree = {"id":1,"label":"A","child":[{"id":2,"label":"B","child":[{"id":5,"label":"E","child":[]},{"id":6,"label":"F","child":[]},{"id":7,"label":"G","child":[]}]},{"id":3,"label":"C","child":[]},{"id":4,"label":"D","child":[{"id":8,"label":"H","child":[]},{"id":9,"label":"I","child":[]}]}]};
console.log(search(tree, 1));
console.log(search(tree, 6));
console.log(search(tree, 99));
You can also do it iteratively with an explicit stack which won't cause a stack overflow (but note that the shorthand stack.push(...curr.child);
can overflow the argument size for some JS engines due to the spread syntax, so use an explicit loop or concat
for massive child arrays):
const search = (tree, target) => {
for (const stack = [tree]; stack.length;) {
const curr = stack.pop();
if (curr.id === target) {
return curr.label;
}
stack.push(...curr.child);
}
};
const tree = {"id":1,"label":"A","child":[{"id":2,"label":"B","child":[{"id":5,"label":"E","child":[]},{"id":6,"label":"F","child":[]},{"id":7,"label":"G","child":[]}]},{"id":3,"label":"C","child":[]},{"id":4,"label":"D","child":[{"id":8,"label":"H","child":[]},{"id":9,"label":"I","child":[]}]}]};
for (let i = 0; ++i < 12; console.log(search(tree, i)));
A somewhat more generic design would return the node itself and let the caller access the .label
property if they want to, or use the object in some other manner.
Note that JSON is purely a string format for serialized (stringified, raw) data. Once you've deserialized JSON into a JavaScript object structure, as is here, it's no longer JSON.
scan
can be written recursively using a third parameter that models a queue of nodes to scan
const scan = (id, tree = {}, queue = [ tree ]) =>
// if id matches node id, return node label
id === tree.id
? tree.label
// base case: queue is empty
// id was not found, return false
: queue.length === 0
? false
// inductive case: at least one node
// recur on next tree node, append node children to queue
: scan (id, queue[0], queue.slice(1).concat(queue[0].child))
Becauase JavaScript supports default arguments, the call site for scan
is unaltered
console.log
( scan (1, tree) // "A"
, scan (3, tree) // "C"
, scan (9, tree) // "I"
, scan (99, tree) // false
)
Verify it works in your browser below
const scan = (id, tree = {}, queue = [ tree ]) =>
id === tree.id
? tree.label
: queue.length === 0
? false
: scan (id, queue[0], queue.slice(1).concat(queue[0].child))
const tree =
{ id: 1
, label: "A"
, child:
[ { id: 2
, label: "B"
, child:
[ { id: 5
, label: "E"
, child: []
}
, { id: 6
, label: "F"
, child: []
}
, { id: 7
, label: "G"
, child: []
}
]
}
, { id: 3
, label: "C"
, child: []
}
, { id: 4
, label: "D"
, child:
[ { id: 8
, label: "H"
, child: []
}
, { id: 9
, label: "I"
, child: []
}
]
}
]
}
console.log
( scan (1, tree) // "A"
, scan (3, tree) // "C"
, scan (9, tree) // "I"
, scan (99, tree) // false
)
Related recursive search using higher-order functions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With