JavaScript数组非扁平化问题:如何正确构建父子层级结构?
非扁平化处理带层级编号的任务数组问题
需要把扁平化的任务数组,按照number属性的层级关系(比如1是1.1的父级,2.1是2.1.1的父级)转换成嵌套结构,但当前用map()+filter()的实现会重复出现已作为子项的元素,比如最终数组里同时有1和1.1,而1.1已经是1的子项了,不符合预期。
现有代码
const arr = [ { name: 'task a', number: '1' }, { name: 'task b', number: '1.1'}, { name: 'task c', number: '1.2' }, { name: 'task d', number: '2' }, { name: 'task e', number: '2.1' }, { name: 'task f', number: '2.1.1' } ]; const output = arr.map((element) => { const re = new RegExp(`^(${element.number}\\.)\\d$`) element.subRows = arr.filter((e) => { return e.number.match(re) }) return element }) output.forEach((x) => { console.log(x) })
预期输出
const data = [ { name: 'task a', number: '1', subRows: [ { name: 'task b', number: '1.1', subRows: [] }, { name: 'task c', number: '1.2', subRows: [] } ] }, { name: 'task d', number: '2', subRows: [ { name: 'task e', number: '2.1', subRows: [ { name: 'task f', number: '2.1.1', subRows: [] } ] }, ] }, ];
问题分析
原代码的核心问题是:遍历了所有元素并给每个元素都添加了subRows,导致子元素(比如1.1、2.1)本身也会出现在最终的output数组里,不符合预期的嵌套结构。
解决方案
我们可以通过建立元素映射表的方式,快速找到父级元素并将子元素挂载到父级的subRows中,最后只保留顶级元素(没有父级的元素),这样就不会有重复项,同时自动处理所有层级:
const arr = [ { name: 'task a', number: '1' }, { name: 'task b', number: '1.1'}, { name: 'task c', number: '1.2' }, { name: 'task d', number: '2' }, { name: 'task e', number: '2.1' }, { name: 'task f', number: '2.1.1' } ]; // 1. 创建以number为键的映射表,同时给每个元素初始化空的subRows const elementMap = arr.reduce((map, item) => { map[item.number] = { ...item, subRows: [] }; return map; }, {}); // 2. 遍历每个元素,找到对应的父级并挂载到父级的subRows arr.forEach(item => { const numberParts = item.number.split('.'); // 只有非顶级元素才有父级(number包含至少一个点) if (numberParts.length > 1) { // 父级number是去掉最后一段的部分,比如2.1.1的父级是2.1 const parentNumber = numberParts.slice(0, -1).join('.'); // 如果父级存在,就把当前元素添加到父级的subRows里 if (elementMap[parentNumber]) { elementMap[parentNumber].subRows.push(elementMap[item.number]); } } }); // 3. 筛选出所有顶级元素(number拆分后只有一段,比如1、2) const output = Object.values(elementMap).filter(item => item.number.split('.').length === 1); console.log(output);
这段代码的逻辑:
- 用
reduce创建映射表,方便O(1)时间查找任意元素 - 遍历每个元素,通过拆分
number找到父级编号,把当前元素挂载到父级的subRows - 最后只保留没有父级的顶级元素,这些元素就是嵌套结构的根节点
运行后输出完全符合预期,且不会出现重复元素,同时支持任意深度的层级嵌套。
内容的提问来源于stack exchange,提问作者WindCheck
相关产品推荐
相关产品推荐

