如何在JavaScript中从扁平数据生成递归嵌套数组结构
将扁平数组转换为深度嵌套树形结构
需求描述
需要将列数不固定但最后一项始终为数值的扁平数组,转换为嵌套的树形结构:遍历每行数组,按层级创建分组节点,非叶子节点包含name和children数组,叶子节点包含name和value(数值类型)。
输入示例
const inputData = [ ["World", "Asia", "Singapore", "Asia-Singapore", "1300"], ["World", "Asia", "India", "Asia-India", "850"], ["World", "Asia-Singapore", "Bond", "Bond-Singapore", "650"], ["World", "Asia-Singapore", "Bond", "Singapore-Bond", "650"], ["World", "Asia-China", "Bond", "Bond-China", "600"], ["World", "Asia-China", "Bond", "China-Bond", "600"], ["World", "Asia-India", "Equity", "Equity-India", "500"], ["World", "Asia-India", "Equity", "India-Equity", "500"], [ "World", "Asia-China", "Private Equity", "China-Private Equity", "400", ], [ "World", "Asia-China", "Private Equity", "Private Equity -China", "400", ], ["World", "Asia-India", "Bond", "Bond-India", "350"], ["World", "Asia-India", "Bond", "India-Bond", "350"], [ "Jupiter", "Asia-Singapore", "Private Equity", "Private Equity -Singapore", "350", ], [ "Jupiter", "Asia-Singapore", "Private Equity", "Singapore-Private Equity", "350", ], ["Jupiter", "Asia-Singapore", "Equity", "Equity-Singapore", "300"], ["Jupiter", "Asia-Singapore", "Equity", "Singapore-Equity", "300"], ["Jupiter", "Asia", "China", "Asia-China", "Franky", "290"], ["World", "Asia-China", "Equity", "China-Equity", "250"], ["World", "Asia-China", "Equity", "Equity-China", "250"], ["World", "Asia", "China", "Asia-China", "Billy", "110"], ["World", "Asia", "China", "Asia-China", "Freddy", "50"], ];
期望输出结构示例
const testData = [ { name: "World", children: [ { name: "Asia", children: [ { name: "Asia-China", value: 110, }, ], }, ], }, { name: "Jupiter", children: [ { name: "Asia-Singapore", children: [ { name: "Google", value: 200, }, ], }, ], }, ];
实现方案
基于层级遍历的思路,实现buildTree函数完成转换:
function buildTree(data) { const result = []; data.forEach((row) => { let currentLevel = result; row.slice(0, -1).forEach((name, index) => { let existing = currentLevel.find((item) => item.name === name); if (!existing) { // 判断当前节点是否为叶子节点(即倒数第二个元素) if (name === row[row.length - 2]) { existing = { name, value: parseInt(row[row.length - 1]), }; } else { existing = { name, children: [], }; } currentLevel.push(existing); } // 如果当前节点有子节点,切换到子节点层级继续处理 if (existing.children) { currentLevel = existing.children; } }); }); return result; }
代码说明
- 初始化结果数组作为根节点层级
- 遍历每一行数据,维护当前处理的层级节点数组
- 对每行除最后一项外的元素逐个处理:
- 检查当前层级是否已存在同名节点,不存在则创建(判断是否为叶子节点,决定带
children还是value) - 若当前节点有子节点,切换到子节点层级继续后续元素的处理
- 检查当前层级是否已存在同名节点,不存在则创建(判断是否为叶子节点,决定带
内容的提问来源于stack exchange,提问作者Frank Packer
相关产品推荐
相关产品推荐

