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

JS实现:如何将表格数据转换为树形JSON结构

解决方案:将扁平路径转换为树形结构

我来帮你搞定这个树形结构转换的问题!你遇到的核心需求是把那些扁平的行数据里的层级路径合并成嵌套的树形结构,我来给你拆解一下解决方案,再附上可运行的代码。

方式一:迭代式构建(直观易懂)

这种方式通过逐层级遍历每个路径,逐步把节点添加到树中,逻辑清晰,容易调试:

const myObjOriginal = { 
  "rows": [
    { "name": "row 1", "cells": [{ "name": "level 1", "id": 1 }, { "name": "first level 2", "id": 2 }, { "name": "endpoint 1", "id": 4 }] }, 
    { "name": "row 2", "cells": [{ "name": "level 1", "id": 1 }, { "name": "first level 2", "id": 2 }, { "name": "endpoint 2", "id": 5 }] }, 
    { "name": "row 3", "cells": [{ "name": "level 1", "id": 1 }, { "name": "second level 2", "id": 3 }, { "name": "endpoint 3", "id": 6 }] }
  ] 
};

function buildTree(rows) {
  const tree = [];
  
  rows.forEach(row => {
    const path = row.cells;
    let currentLevel = tree;
    
    path.forEach((node, index) => {
      // 用id判断当前层级是否已有该节点(id是唯一标识,比name更可靠)
      let existingNode = currentLevel.find(item => item.id === node.id);
      
      if (!existingNode) {
        // 创建新节点,只有非叶子节点才需要children数组
        const newNode = { ...node };
        if (index !== path.length - 1) {
          newNode.children = [];
        }
        currentLevel.push(newNode);
        existingNode = newNode;
      }
      
      // 移动到下一层级,继续处理路径的剩余部分
      if (index !== path.length - 1) {
        currentLevel = existingNode.children;
      }
    });
  });
  
  return tree;
}

// 生成目标树形结构
const goalObject = buildTree(myObjOriginal.rows);
console.log(JSON.stringify(goalObject, null, 2));

代码逻辑说明:

  1. 初始化一个空数组作为树的根层级
  2. 遍历每一行数据,取出该行的cells作为一条完整的路径
  3. 对路径上的每个节点,从当前层级开始检查:
    • 如果当前层级没有这个id的节点,就创建新节点并加入当前层级
    • 如果是叶子节点(路径的最后一个节点),不需要添加children属性
  4. 每次处理完一个节点后,把当前层级切换到该节点的children(如果不是叶子节点),继续处理路径的剩余部分

方式二:递归式构建(代码更简洁)

如果你偏好递归写法,也可以用辅助函数来递归处理每个路径的剩余部分:

function buildTreeRecursive(rows) {
  // 辅助函数:把一条路径添加到指定的树层级中
  const addPathToTree = (tree, path) => {
    if (path.length === 0) return;
    
    // 解构出路径的第一个节点和剩余部分
    const [currentNode, ...remainingPath] = path;
    // 检查当前层级是否已有该节点
    let existingNode = tree.find(item => item.id === currentNode.id);
    
    if (!existingNode) {
      existingNode = { ...currentNode };
      // 如果还有剩余路径,说明当前节点不是叶子,需要children
      if (remainingPath.length > 0) {
        existingNode.children = [];
      }
      tree.push(existingNode);
    }
    
    // 递归处理剩余路径到当前节点的children中
    if (remainingPath.length > 0) {
      addPathToTree(existingNode.children, remainingPath);
    }
  };
  
  const tree = [];
  rows.forEach(row => addPathToTree(tree, row.cells));
  return tree;
}

const goalObjectRecursive = buildTreeRecursive(myObjOriginal.rows);
console.log(JSON.stringify(goalObjectRecursive, null, 2));

为什么你的尝试没成功?

你之前的代码逻辑比较零散,没有清晰地跟踪当前处理的层级,也没有正确判断节点是否已经存在。而上面的两种方法都聚焦于路径的逐层级合并,通过明确的层级跟踪和节点存在性检查,就能轻松实现树形结构的构建。

运行上面的代码,你会得到和目标格式一致的结果(注意你给出的goalObject里level 1的id写错了,应该是1,代码会自动使用原始数据的正确id)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:48:58