如何将扁平对象数组转换为以ID为键的多层嵌套对象?
我太懂这种多层嵌套绕晕的感觉了——之前处理类似结构时,一开始用递归找父节点,结果数据量一大就卡,还容易出现层级丢失的问题。这里有个高效的动态解法,不管是3层还是更多层都能轻松搞定,核心是用映射表来快速定位父节点,不用反复遍历数组。
解决方案
核心思路拆解
- 先建一个ID到对象的映射表:把每个对象的ID作为键,对象本身作为值,这样找父节点能直接O(1)定位,不用循环遍历整个数组。
- 遍历处理每个节点:根节点(
parent="0")单独收集,非根节点直接挂到对应父节点的children数组里(没有children就先初始化)。 - 最后按需输出:可以是根节点数组,也可以转成以根节点ID为键的嵌套对象。
代码示例(JavaScript)
先拿你给的类似输入举个例子,假设输入数组是这样的:
const input = [ { ID: "1671", parent: "0", name: "部门A" }, { ID: "1672", parent: "1671", name: "小组A1" }, { ID: "1673", parent: "1672", name: "成员A1-1" }, { ID: "1674", parent: "0", name: "部门B" }, { ID: "1675", parent: "1674", name: "小组B1" } ];
然后写处理函数:
function buildNestedTree(arr) { // 1. 建立ID映射表,同时给每个节点初始化children数组(避免修改原数据,用浅拷贝) const idMap = {}; const rootNodes = []; // 第一步:填充映射表 arr.forEach(item => { idMap[item.ID] = { ...item, children: [] }; }); // 第二步:把每个节点挂载到父节点下 arr.forEach(item => { const currentNode = idMap[item.ID]; if (item.parent === "0") { // 根节点直接加入根数组 rootNodes.push(currentNode); } else { // 找到父节点,将当前节点加入children const parentNode = idMap[item.parent]; if (parentNode) { // 防止输入里有无效的parent ID parentNode.children.push(currentNode); } } }); // 如果需要以根节点ID为键的对象,取消下面注释即可 // const nestedObject = {}; // rootNodes.forEach(node => { // nestedObject[node.ID] = node; // }); // return nestedObject; // 默认返回根节点数组,适合大多数树形展示场景 return rootNodes; } // 调用函数获取结果 const nestedTree = buildNestedTree(input); console.log(JSON.stringify(nestedTree, null, 2));
运行结果示例
执行后会得到这样的嵌套结构(格式化后):
[ { "ID": "1671", "parent": "0", "name": "部门A", "children": [ { "ID": "1672", "parent": "1671", "name": "小组A1", "children": [ { "ID": "1673", "parent": "1672", "name": "成员A1-1", "children": [] } ] } ] }, { "ID": "1674", "parent": "0", "name": "部门B", "children": [ { "ID": "1675", "parent": "1674", "name": "小组B1", "children": [] } ] } ]
为什么这个方法好用?
- 效率高:只遍历数组两次,时间复杂度O(n),数据量大的时候优势明显。
- 支持任意深度:不管是3层还是更深的嵌套,逻辑都能自动处理,不用改代码。
- 容错性强:如果输入里有无效的parent ID(比如父节点不存在),会自动跳过,不会报错。
- 不修改原数据:用浅拷贝创建新对象,不会影响输入的原始数组。
内容的提问来源于stack exchange,提问作者Anthony O'Neill
相关产品推荐
相关产品推荐

