以分层树结构打印姓氏

问题描述

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

样本输入:

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

输出

BCA
    ABC
        CBA
        DDA
    EFG

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

const data = [{ id: 1,parent: 2 },{ id: 2,name: "BCA" },{ id: 3,parent: 1 },{ id: 4,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 是正确的操作,因为我们希望构建从每个节点到其子节点的平面映射,然后返回根节点。需要每个节点的 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",{
    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,parent: 2},{id: 2,name: "BCA"},{id: 3,parent: 1},{id: 4,{id: 5,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,parent: 2}];

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