从平面对象数组构建对象树数组[重复]

Posted

技术标签:

【中文标题】从平面对象数组构建对象树数组[重复]【英文标题】:Building tree array of objects from flat array of objects [duplicate] 【发布时间】:2017-10-20 10:48:57 【问题描述】:

我想从平面数组构建一个树数组:

这是平面数组:

nodes = [
    id: 1, pid: 0, name: "kpittu",
    id: 2, pid: 0, name: "news",
    id: 3, pid: 0, name: "menu",
    id: 4, pid: 3, name: "node",
    id: 5, pid: 4, name: "subnode",
    id: 6, pid: 1, name: "cace"
];

注意:id = 节点id; pid = 父节点 ID。

我想把它变成这个数组:

nodes = [
    id: 1,
    name: 'kpittu',
    childs: [
        id: 6,
        name: 'cace'
    ]
, 
    id: 2,
    name: 'news'
, 
    id: 3,
    name: 'menu',
    childs: [
        id: 4,
        name: 'node',
        childs: [
            id: 5,
            name: 'subnode'
        ]
    ]
];

我尝试使用递归函数来实现预期结果,但我正在寻找更好的方法。感谢您的回复。

【问题讨论】:

请同时添加您的功能。 建议,如果你自己不弄清楚,你将无法学习或练习你的递归知识,而是回答这个问题的人 【参考方案1】:

您可以使用哈希表并将每个循环中的idpid 作为连接节点。

此提议也适用于未排序的数据。

var nodes = [ id: 6, pid: 1, name: "cace" ,  id: 1, pid: 0, name: "kpittu" ,  id: 2, pid: 0, name: "news" ,  id: 3, pid: 0, name: "menu" ,  id: 4, pid: 3, name: "node" ,  id: 5, pid: 4, name: "subnode" ],
    tree = function (data, root) 
        var r = [], o = ;
        data.forEach(function (a) 
            if (o[a.id] && o[a.id].children) 
                a.children = o[a.id] && o[a.id].children;
            
            o[a.id] = a;
            if (a.pid === root) 
                r.push(a);
             else 
                o[a.pid] = o[a.pid] || ;
                o[a.pid].children = o[a.pid].children || [];
                o[a.pid].children.push(a);
            
        );
        return r;
    (nodes, 0);

console.log(tree);
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

【参考方案2】:

你也可以使用 ES6 中引入的 Map 对象。

let nodes = [
   id: 1, pid: 0, name: "kpittu" ,
   id: 2, pid: 0, name: "news" ,
   id: 3, pid: 0, name: "menu" ,
   id: 4, pid: 3, name: "node" ,
   id: 5, pid: 4, name: "subnode" ,
   id: 6, pid: 1, name: "cace" 
];

function toTree(arr) 
  let arrMap = new Map(arr.map(item => [item.id, item]));
  let tree = [];

  for (let i = 0; i < arr.length; i++) 
    let item = arr[i];

    if (item.pid) 
      let parentItem = arrMap.get(item.pid);

      if (parentItem) 
        let  children  = parentItem;

        if (children) 
          parentItem.children.push(item);
         else 
          parentItem.children = [item];
        
      
     else 
      tree.push(item);
    
  

  return tree;


let tree = toTree(nodes);

console.log(tree);

【讨论】:

【参考方案3】:

使用 Array#reduce 和辅助对象进行迭代:

var nodes = [
  id: 1, pid: 0, name: "kpittu",
  id: 2, pid: 0, name: "news",
  id: 3, pid: 0, name: "menu",
  id: 4, pid: 3, name: "node",
  id: 5, pid: 4, name: "subnode",
  id: 6, pid: 1, name: "cace"
];

const helper = nodes.reduce((h, o) => (h[o.id] = Object.assign(, o), h), Object.create(null));

const tree = nodes.reduce((t, node) => 
  const current = helper[node.id];
  
  if(current.pid === 0)  // if it doesn't have a parent push to root
    t.push(current);
   else 
    helper[node.pid].children || (helper[node.pid].children = []) // add the children array to the parent, if it doesn't exist
    helper[node.pid].children.push(current); // push the current item to the parent children array
  
  
  return t;
, []);

console.log(tree);

【讨论】:

以上是关于从平面对象数组构建对象树数组[重复]的主要内容,如果未能解决你的问题,请参考以下文章

从对象树构造平面数组

将平面对象数组转换为嵌套对象数组[重复]

从数组中删除重复的对象

从 PHP 中的平面路径数组构建目录树

将嵌套的 mongoDB 文档转换为平面 pandas DataFrame(对象数组中的对象数组)

从对象数组中删除第二次出现的对象[重复]