Javascript递归树构建

时间:2017-04-07 14:20:47

标签: javascript algorithm tree

我遇到了从平面阵列构建树的问题。我正在建立一个类别 - >子类别树,其中父类具有子类别作为数组。

这是平面阵列的样子:

[
  {
    "id": 1
  },
  {
    "id": 5,
  },
  {
    "id": 2,
    "parent_id": 1
  },
  {
    "id": 3,
    "parent_id": 1
  },
  {
    "id": 42,
    "parent_id": 5
  },
  {
    "id": 67,
    "parent_id": 5
  }
]

这就是我需要的结果:

[
  {
    "id":1,
    "subcategories":[
      {
        "id":2,
        "parent_id":1
      },
      {
        "id":3,
        "parent_id":1
      }
    ]
  },
  {
    "id":5,
    "subcategories":[
      {
        "id":42,
        "parent_id":5
      },
      {
        "id":67,
        "parent_id":5
      }
    ]
  }
]

我试图通过递归搜索子项并将其作为数组附加来递归地执行此操作,并继续这样做,直到我击中桶的底部但我得到一个循环结构。似乎遍历中的parent_id始终是父级的id ...任何想法:

tree(passingInFlatObjectHere);

function topLevel (data) {
  let blob = [];
  data.forEach((each) => {
    if (!each.parent_id) {
      blob.push(each);
    }
  });
  return blob;
}

function tree (data) {
  let blob = topLevel(data).map(function (each) {
    each.subcategories = traverse(data, each.id);
    return each;
  });
  return blob;
}

function traverse (data, parent_id) {
  let blob = [];
  if (!parent_id) {
    return blob;
  }
  data.forEach((each) => {
    if (each.id === parent_id) {
      each.subcategories = traverse(data, each.id);
      blob.push(each);
    }
  });
  return blob;
}

1 个答案:

答案 0 :(得分:1)

我不仅希望帮助您解决问题,还希望帮助您充分利用ES6

首先,您的topLevel函数可以重写为:

function topLevel(data) {
  return data.filter(node => !node.parent_id);
}

整洁不是吗?我还建议稍微更改tree以保持一致性,但这当然只是风格。

function tree(data) {
  return topLevel(data).map(each => {
    each.subcategories = traverse(data, each.id);
    return each;
  });
}

到目前为止还没有逻辑问题。但是,当您检查traverse时,each.id === parent_id包含一个。像这样,函数搜索id为parent_id的节点。显然是个错误。你想要each.parent_id === parent_id

您的问题现已解决。如果我打扰你就停止阅读。但是你也可以在这里利用filter并删除稍微多余的早期退出并将你的函数重写为:

function traverse(data, parentId) {
  const children = data.filter(each => each.parent_id === parentId);
  children.forEach(child => {
    child.subcategories = traverse(data, child.id);
  });
  return children;
}