Skip to content

Print family names in a hierarchical tree structure

There is an array of data objects which have parent and child relations in it. I’d like to print the structure of the tree by level, printing only the names. If there is no parent information indicated then it is the root node.

Sample input:

data = [
  {
      id: 1,
      name: "ABC",
      parent: 2
  },
  {
      id: 2,
      name: "BCA"
  },
  {
     id: 3,
     name: "CBA",
     parent: 1
  },
  {
    id: 4,
    name: "DDA",
    parent: 1
  },
  {
    id: 5,
    name: "EFG",
    parent: 2
  }
];

Output:

BCA
    ABC
        CBA
        DDA
    EFG

I tried using reduce to get the object structure but couldn’t get the traverse logic. Is there better way to get the solution, such that all the child objects will be under a single array?

const data = [{ id: 1, name: "ABC", parent: 2 },
{ id: 2, name: "BCA" },
{ id: 3, name: "CBA", parent: 1 },
{ id: 4, name: "DDA", parent: 1 }];

let root = null;

const obj = data.reduce((r, o) => {
    Object.assign(r[o.id] = r[o.id] || {}, o);
    if (!o.parent) {
        root = o.id;
    }
    r[o.parent] = r[o.parent] || {};
    r[o.parent][o.id] = r[o.id];
    return r;
}, {});
console.log(obj[root]);

Answer

reduce is the correct operation because we want to build flat mapping from every node to its children, then return the root. The children array for each node is needed so we can traverse and print the tree top-down. If parent references were enough, we’d be done since the original structure already has these.

One approach to produce the nested structure is:

const unflattenTree = data => {
  const nodes = {};
  let root;

  for (const node of data) {
    nodes[node.id] = {children: [], ...nodes[node.id], ...node};
    
    if (node.parent) {
      nodes[node.parent] = {children: [], ...nodes[node.parent]};
      nodes[node.parent].children.push(nodes[node.id]);
    }
    else {
      root = nodes[node.id];
    }
  }

  return root;
};

const printTree = (root, gap=4, level=0) => {
  if (root) {
    console.log(" ".repeat(level), root.name);
    root.children?.forEach(e => printTree(e, gap, level + gap));
  }
};

const data = [
  {
    id: 1,
    name: "ABC",
    parent: 2
  },
  {
    id: 2,
    name: "BCA"
  },
  {
    id: 3,
    name: "CBA",
    parent: 1
  },
  {
    id: 4,
    name: "DDA",
    parent: 1
  },
  {
    id: 5,
    name: "EFG",
    parent: 2
  }
];

printTree(unflattenTree(data));