为数组对象添加hierarchy属性时,使用lodash find遇parent未定义问题
问题描述
原始数组:
const arr = [ {name: "Earth", id: 1, parent_id: -1}, {name: "Europe", id: 2, parent_id: 1}, {name: "America", id: 3, parent_id: 1}, {name: "Asia", id: 4, parent_id: 1} ];
需求:为数组每个元素添加hierarchy键,使其包含层级名称数组,最终效果如下:
const arr = [ {name: "Earth", id: 1, parent_id: -1, hierarchy: ["Earth"]}, {name: "Europe", id: 2, parent_id: 1, hierarchy: ["Earth", "Europe"]}, {name: "America", id: 3, parent_id: 1, hierarchy: ["Earth", "America"]}, {name: "Asia", id: 4, parent_id: 1, hierarchy: ["Earth", "Asia"]} ];
尝试用Lodash的find方法实现,但始终得到parent === undefined的结果,代码如下:
const parent = _.find(arr, { id: val.parent_id }); if (parent === undefined) { val.hierarchy = [val.id]; } else { val.hierarchy = [...parent.hierarchy, val.id]; }
解决方案
问题原因分析
- 遍历顺序错误:如果先处理子节点再处理根节点,即使原数组存在父节点,也可能因父节点未完成
hierarchy属性添加(或错误地在未构建完成的新数组中查找)导致找不到;另外根节点parent_id=-1时,原数组无对应id元素,这部分undefined是正常的,但原代码错误地将val.id存入hierarchy,不符合需求的名称要求。 - 查找逻辑缺陷:直接用
_.find遍历数组找父节点,效率低且易受遍历顺序影响。
正确实现方式
方式一:构建ID映射表(推荐)
先将数组转为以id为键的映射表,快速查找任意节点,不受遍历顺序限制:
const arr = [ {name: "Earth", id: 1, parent_id: -1}, {name: "Europe", id: 2, parent_id: 1}, {name: "America", id: 3, parent_id: 1}, {name: "Asia", id: 4, parent_id: 1} ]; // 构建ID到节点的映射 const nodeMap = _.keyBy(arr, 'id'); // 遍历节点构建层级数组 const result = arr.map(node => { const hierarchy = []; let current = node; // 向上遍历直到根节点 while (current) { hierarchy.unshift(current.name); current = nodeMap[current.parent_id]; } return {...node, hierarchy}; }); console.log(result);
方式二:按层级顺序遍历
先处理根节点,确保子节点处理时父节点已完成hierarchy添加:
const arr = [ {name: "Earth", id: 1, parent_id: -1}, {name: "Europe", id: 2, parent_id: 1}, {name: "America", id: 3, parent_id: 1}, {name: "Asia", id: 4, parent_id: 1} ]; // 复制原数组避免修改原数据 const result = [...arr]; // 先处理根节点 const root = result.find(item => item.parent_id === -1); root.hierarchy = [root.name]; // 处理一级子节点(多级嵌套需递归/层级遍历) result.forEach(item => { if (item.parent_id !== -1) { const parent = result.find(p => p.id === item.parent_id); item.hierarchy = [...parent.hierarchy, item.name]; } }); console.log(result);
修复原代码逻辑
如果坚持使用原逻辑,需调整遍历顺序并修正层级内容:
const arr = [ {name: "Earth", id: 1, parent_id: -1}, {name: "Europe", id: 2, parent_id: 1}, {name: "America", id: 3, parent_id: 1}, {name: "Asia", id: 4, parent_id: 1} ]; // 先处理根节点 const root = _.find(arr, {parent_id: -1}); root.hierarchy = [root.name]; // 再处理其他节点 arr.forEach(val => { if (val.parent_id !== -1) { const parent = _.find(arr, { id: val.parent_id }); val.hierarchy = [...parent.hierarchy, val.name]; } }); console.log(arr);
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

