Ayoub k
Ayoub k

Reputation: 8868

Get all parent in a nested object using recursion

I have the following object

const object = {
    id: "1",
    name: "a",
    children: [
        {
            id: "2",
            name: "b",
            children: [
                {
                    id: "3",
                    name: "c"
                }
            ]
        },
        {
            id: "4",
            name: "d"
        }
    ]
};

I need a function that accept the object and the id of the last child and return the path, for example, the following call: getPath(object, '3'); should return [{id: 1}, {id: 2}, {id: 3}].

I created the function but I can access only to the first parent.

function getPath(model, id, parent) {
    if (model == null) {
        return;
    }
    if (model.id === id) {
        console.log(model.id, parent.id)
    }
    if (model.children) {
        model.children.forEach(child => getPath(child, id, model));
    }
}

PS: The object has an unknown depth.

Upvotes: 7

Views: 2430

Answers (3)

xdeepakv
xdeepakv

Reputation: 8125

const object = {
  id: "1",
  name: "a",
  children: [
    {
      id: "2",
      name: "b",
      children: [
        {
          id: "3",
          name: "c"
        },
        {
          id: "5",
          name: "c"
        }
      ]
    },
    {
      id: "4",
      name: "d"
    }
  ]
};

const getPath = (obj, id, paths = []) => {
  if (obj.id == id) return [{ id: obj.id }];
  if (obj.children && obj.children.length) {
    paths.push({ id: obj.id });
    let found = false;
    obj.children.forEach(child => {
      const temPaths = getPath(child, id);
      if (temPaths) {
        paths = paths.concat(temPaths);
        found = true;
      }
    });
    !found && paths.pop();
    return paths;
  }
  return null;
};
console.log(getPath(object, "5"));
console.log(getPath(object, "2"));
console.log(getPath(object, "3"));
console.log(getPath(object, "4"));
.as-console-row {color: blue!important}

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386520

You could use a short circuit for iterating the children and hand over the path from the function with the target object.

function getPath(model, id) {
    var path,
        item = { id: model.id };

    if (!model || typeof model !== 'object') return;

    if (model.id === id) return [item];    
    
    (model.children || []).some(child => path = getPath(child, id));
    return path && [item, ...path];
    
}
const object = { id: "1", name: "a", children: [{ id: "2", name: "b", children: [{ id: "3", name: "c" }] }, { id: "4", name: "d" }] };

console.log(getPath(object, '42')); // undefined
console.log(getPath(object, '3'));  // [{ id: 1 }, { id: 2 }, { id: 3 }]
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 7

Nick
Nick

Reputation: 16576

This is pretty close. Consider passing the entire path array in your recursive function. The following is a slightly modified version of what you have that accomplishes this.

function getPath(model, id, path) {
    if (!path) {
      path = [];
    }

    if (model == null) {
        return;
    }
    if (model.id === id) {
        console.log(model.id, path)
    }
    if (model.children) {
        model.children.forEach(child => getPath(child, id, [...path, model.id]));
    }
}

const object = {
    id: "1",
    name: "a",
    children: [
        {
            id: "2",
            name: "b",
            children: [
                {
                    id: "3",
                    name: "c"
                }
            ]
        },
        {
            id: "4",
            name: "d"
        }
    ]
};

getPath(object, "3");

Upvotes: 6

Related Questions