You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中通过parentId和Id将扁平数组转为树形数组?

实现扁平数组转树形结构的两种常用方法

嘿,这个需求我做项目时经常碰到,把扁平数组转成树形结构其实不难,这里给你分享两种实用的实现思路,你可以根据自己的场景选择:

方法一:利用哈希表(Map)快速查找父节点(高效推荐)

这种方法时间复杂度是O(n),不管数据量多大都能高效处理,核心是先把所有节点存到Map里,再遍历每个节点找到父节点并添加到children中:

function flatToTree(arr) {
  // 创建Map存储每个节点,方便快速查找
  const nodeMap = new Map();
  // 存放最终的树形结构(根节点集合)
  const tree = [];

  // 第一步:把所有节点存入Map,同时初始化children属性
  arr.forEach(node => {
    nodeMap.set(node.id, { ...node, children: [] });
  });

  // 第二步:遍历节点,将子节点挂载到对应父节点下
  arr.forEach(node => {
    if (node.pid !== null) {
      const parent = nodeMap.get(node.pid);
      parent.children.push(nodeMap.get(node.id));
    } else {
      // pid为null的是根节点,直接加入树形数组
      tree.push(nodeMap.get(node.id));
    }
  });

  return tree;
}

// 测试你的数据
const a = [ 
  {id: 1, pid: null}, 
  {id: 2, pid: 1}, 
  {id: 3, pid: 1}, 
  {id: 4, pid: 3}, 
  {id: 5, pid: 3} 
];
const result = flatToTree(a);
console.log(result);

运行后输出的结果完全符合你的期望~

方法二:递归查找父节点(适合小数据量,逻辑直观)

如果你的数据量不大,递归方式会更直观易懂,核心是每次递归找到当前节点的所有子节点:

function flatToTreeRecursive(arr, pid = null) {
  // 过滤出当前pid对应的子节点,再递归查找每个子节点的子节点
  return arr.filter(node => node.pid === pid).map(node => ({
    ...node,
    children: flatToTreeRecursive(arr, node.id)
  }));
}

// 测试
const a = [ 
  {id: 1, pid: null}, 
  {id: 2, pid: 1}, 
  {id: 3, pid: 1}, 
  {id: 4, pid: 3}, 
  {id: 5, pid: 3} 
];
const result = flatToTreeRecursive(a);
console.log(result);

这个方法逻辑简单:先筛选出对应父id的节点,再对每个节点递归生成子树。不过要注意,数据量大时递归的性能会比第一种方法差,因为每次filter都会遍历整个数组。

补充说明

  • 两种方法都会自动给每个节点添加children属性,没有子节点时就是空数组,和你期望的输出格式一致。
  • 如果数组里有多个根节点(多个pid为null的节点),两种方法都能正确处理,会把所有根节点都放到结果数组中。

内容的提问来源于stack exchange,提问作者Xinyi Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:09:18