以分层树结构打印姓氏

Print family names in a hierarchical tree structure

有一个数据对象数组,其中有父子关系。我想按级别打印树的结构,只打印名称。如果没有指明父节点信息则为根节点。

示例输入:

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
  }
];

输出:

BCA
    ABC
        CBA
        DDA
    EFG

我尝试使用reduce 获取对象结构但无法获取遍历逻辑。有没有更好的方法来获得解决方案,以便所有子对象都在一个数组下?

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]);

reduce 是正确的操作,因为我们要构建从每个节点到其子节点的平面映射,然后是 return 根节点。需要每个节点的 children 数组,以便我们可以自上而下地遍历和打印树。如果 parent 个引用就足够了,我们就完成了,因为原始结构已经有了这些。

生成嵌套结构的一种方法是:

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));

一种非常简单但效率低下的方法就是扫描其父节点与特定 ID 匹配的节点,然后使用它们的 ID 重复查找它们的子节点。

const display = (data, id = null, d = 0) => data 
  .filter (({parent}) => parent == id)
  .map (node => '    ' .repeat (d) + node.name  + `\n` +  
        display (data, node.id, d + 1)) .join('')


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}];

console .log (display (data))
.as-console-wrapper {max-height: 100% !important; top: 0}

如果你想生成数据结构(不是树,而是森林,因为可能有多个根),就这么简单:

const renest = (data, id = null) => data 
  .filter (({parent}) => parent == id)
  .map ((node) => ({...node, children: renest (data, node.id)}))

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}];

console .log (renest (data))
.as-console-wrapper {max-height: 100% !important; top: 0}