【问题标题】:How could I build a tree array from this flat array in Javascript by their's parentId and Id.我如何通过他们的 parentId 和 Id 从 Javascript 中的这个平面数组构建一个树数组。
【发布时间】:2018-03-20 20:02:08
【问题描述】:

我有一个这样的平面数组,我应该为它构建一个平面数组。如果 pid 不为 null,则该对象将是其父对象的子属性。我该怎么做?

    var a = [
        {id: 1, pid: null}, 
        {id: 2, pid: 1}, 
        {id: 3, pid: 1}, 
        {id: 4, pid: 3}, 
        {id: 5, pid: 3}
     ];

期望输出:

     var result = [{id: 1, children: [
        {id: 2, children: []},
        {id: 3, children: [{id: 4}, {id: 5}]}
    ]}]

【问题讨论】:

标签: javascript arrays object tree


【解决方案1】:

您可以使用单循环方法,该方法也适用于未排序的数组。

var a = [{ id: 1, pid: null }, { id: 2, pid: 1 }, { id: 3, pid: 1 }, { id: 4, pid: 3 }, { id: 5, pid: 3 }],
    tree = function (data, root) {
        return data.reduce(function (o, { id, pid }) {
            o[id] = o[id] || { id };
            o[pid] = o[pid] || { id: pid };
            o[pid].children = o[pid].children || [];
            o[pid].children.push(o[id]);
            return o;
        }, {})[root].children;
    }(a, null);

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

【讨论】:

  • 有没有办法得到一个特定的子树而不是整棵树? getChildTree(array,id)?
  • @rendom,您可以将想要的 id 的父代替换为树的 null。
  • 有没有办法将树转换回列表?
  • @rendom,是的,可以通过遍历树并移交父级来实现。
【解决方案2】:

您可以使用reduce() 方法并创建递归函数。

var a = [{id: 1, pid: null}, {id: 2, pid: 1}, {id: 3, pid: 1}, {id: 4, pid: 3}, {id: 5, pid: 3}];

function tree(data, parent) {
  return data.reduce((r, {id,pid}) => {
    if (parent == pid) {
      const obj = {id}
      const children = tree(data, id);
      if (children.length) obj.children = children;
      r.push(obj)
    }
    return r;
  }, [])
}

const result = tree(a, null);
console.log(result);

【讨论】:

  • 谢谢。但我想知道如果我希望我的输出完全像“var result =........”我该怎么办。我的意思是,以“var result ="
  • 不确定你在问什么。
  • 现在你的方法的输出是一个数组树。如果我想要像“var result =.....(数组树放在这里)”这样的格式怎么办。
【解决方案3】:

这里使用 reduce 的两个答案都很好,一个小问题是两者都有多遍,IOW:如果树很大,就会有很多线性搜索。

对此的一种解决方案是先构建地图,然后将地图展平.. 嗯,实际上展平在这里可能是错误的词,也许是展开.. :) 但你明白了..

下面是一个例子。

const a = [
    {id: 1, pid: null}, 
    {id: 2, pid: 1}, 
    {id: 3, pid: 1}, 
    {id: 4, pid: 3}, 
    {id: 5, pid: 3}
 ];
 
 
function flatern(map, parent) {
  const g = map.get(parent);
  const ret = [];
  if (g) {
    for (const id of g) {
      const k = {id};
      ret.push(k);
      const sub = flatern(map, id);
      if (sub) k.children = sub;
    }
    return ret;
  }
  return null;
}
     
function tree(a) {
  const m = new Map();
  a.forEach((i) => {
    const g = m.get(i.pid);
    if (!g) {
      m.set(i.pid, [i.id]);
    } else {
      g.push(i.id);
    }
  });
  return flatern(m, null);
}

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

【讨论】:

  • 顺便说一句,由于哈希表,我的方法使用了一个不进行搜索的对象。访问是 O(1)。
  • @NinaScholz 不错,必须承认并没有真正详细检查代码.. 你的看起来比我的容易,所以我赞成你的.. 我会把我的留在这里给那些发现它更容易阅读/理解。
  • 您好,非常感谢。但是我很难理解“if (sub) k.children = sub;”是什么意思,你能解释一下为什么 sub 上有一个 () 吗?
  • 这只是表示是否有任何子项,并且它们是子项。
【解决方案4】:
    var a = [
        {id: 1, pid: null}, 
        {id: 2, pid: 1}, 
        {id: 3, pid: 1}, 
        {id: 4, pid: 3}, 
        {id: 5, pid: 3}
    ];

    function processToTree(data) {
        const map = {};
        data.forEach(item => {
            map[item.id] = item;
            item.children = [];
        });

        const roots = [];
        data.forEach(item => {
            const parent = map[item.pid];
            if (parent) {
                parent.children.push(item);
            }
            else {
                roots.push(item);
            }
        });
        return roots;
    }

今天学习了这个方法,我觉得这个最好了

【讨论】:

    猜你喜欢
    • 2022-11-16
    • 2021-02-13
    • 1970-01-01
    • 2016-09-25
    • 1970-01-01
    • 2019-10-12
    • 2021-04-19
    • 2012-11-04
    • 1970-01-01
    相关资源
    最近更新 更多