Reputation: 4950
I have a large JSON object that serves a purpose of the tree source. within this JSON I need to find an object with a given ID and build the complete to it meaning collecting its parents. To illustrate it's like in the file system: folde1/folder2/folder3/file.txt. Here is my recursive function to find the object:
private find(source, id): string[] {
for (const key in source)
{
var item = source[key];
if (item.id === id) {
return this.indexes;
}
if (item.children) {
this.indexes.push(key);
var subresult = this.find(item.children, id);
if (subresult) {
this.indexes.push(key);
return this.indexes;
}
}
}
return null;
}
My problem is that while looking for the object I am picking up a lot of false parents thus the result has extra data.
Any idea how make it work? I am also thinking to start looking for the path from the inside, but dont know how to get a parent of the found object.
Thanks for the help.
Upvotes: 0
Views: 1328
Reputation: 328398
I'm going to make a general answer and hopefully it applies to your actual structure. I assume a Tree
looks like this:
interface Tree {
id: string;
children?: Record<string, Tree>;
}
Each Tree
has an id
, and an optional children
property which is a dictionary of Tree
s. A possible implementation of findPathById()
follows:
function findPathById(tree: Tree, id: string, curPath: string[] = []): string[] | undefined {
if (tree.id === id) return curPath;
const children = tree.children ?? {}
for (let k in children) {
const possibleAnswer = findPathById(children[k], id, [...curPath, k]);
if (possibleAnswer) return possibleAnswer;
}
return undefined;
}
The approach here is that the function takes a parameter curPath
corresponding to the path to the current tree node, to which subsequent path entries can be appended. If this path is left out, then it will be assumed to be empty. If the tree
passed in has the desired id
, then we've found it and can return curPath
. Otherwise, we start checking each property of children
(if it exists) to see if the id exists in one of the children, calling findPathId
on the child value, with a new curPath
made by appending the child key to the current path. If we get a result, we return it. Otherwise, we go on to the next child. If we haven't found the id after checking the current item and recursively down through its children, then it isn't in there, and we return undefined
.
Here's a test:
const tree: Tree = {
id: "A",
children: {
x: {
id: "B", children: {
t: { id: "E" },
u: { id: "F" }
}
},
y: {
id: "C", children: {
v: { id: "G" },
w: { id: "H" }
}
},
z: { id: "D" }
}
}
console.log(findPathById(tree, "A")); // []
console.log(findPathById(tree, "D")); // ["z"]
console.log(findPathById(tree, "G")); // ["y", "v"]
console.log(findPathById(tree, "J")); // undefined
This looks like the behavior we want. The "A"
id is found at the root, so the path is an empty array. The "D"
id is found at tree.children.z
, so the path is ["z"]
. The "G"
id is found at tree.children.y.children.v
, so the path is ["y", "v"]
. And finally, the "J"
id is never found, so the path is undefined
.
Upvotes: 1