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

如何将平级待办事项数据转换为支持多级嵌套的层级JSON对象?

如何将平级待办事项数据转换为支持多级嵌套的层级JSON对象?

你好!你的思路其实已经找对方向了——先提取根节点再匹配子节点,但当前实现只能支持两级嵌套。如果要处理任意深度的层级结构,我们可以优化成递归或者用映射表的方式,既灵活又能保证性能,下面给你两种实用的方案,适配Next.js项目的最佳实践:

方案1:映射表优化版(高性能首选)

这种方式先把所有数据用ID做一个快速映射表,后续查找父节点/子节点都是O(1)的时间复杂度,整体时间复杂度O(n),适合处理大量待办数据的场景:

const data = [
    {id: 2, Name:"Task 1.1", ParentID: 1},
    {id: 5, Name:"Task 2", ParentID: null},
    {id: 6, Name:"Task 2.1", ParentID: 5},
    {id: 1, Name:"Task 1", ParentID: null},
    {id: 3, Name:"Task 1.2", ParentID: 1},
    {id: 4, Name:"Task 1.3", ParentID: 1},
    {id: 7, Name:"Task 2.2", ParentID: 5},
    {id: 8, Name:"Task 2.3", ParentID: 5},
    {id: 9, Name:"Task 3", ParentID: null},
    // 可以加个深层节点测试:{id:10, Name:"Task 1.1.1", ParentID:2}
];

function buildHierarchy(data) {
    // 第一步:创建ID到节点的映射,给每个节点初始化subtasks数组
    const taskMap = new Map();
    data.forEach(task => {
        taskMap.set(task.id, {...task, subtasks: []});
    });

    const result = [];

    // 第二步:遍历所有节点,把非根节点挂载到对应父节点的subtasks里
    data.forEach(task => {
        if (task.ParentID === null) {
            // 根节点直接加入最终结果数组
            result.push(taskMap.get(task.id));
        } else {
            // 找到当前节点的父节点,把自己加入父节点的subtasks
            const parentTask = taskMap.get(task.ParentID);
            if (parentTask) {
                parentTask.subtasks.push(taskMap.get(task.id));
            }
        }
    });

    return result;
}

const result = buildHierarchy(data);
console.log(JSON.stringify(result, null, 2));

方案2:递归查找版(代码简洁直观)

如果你的待办数据量不大,想要更简洁的代码,可以用递归函数直接给每个节点查找子节点,逻辑非常直观:

const data = [/* 同上数据 */];

function buildHierarchy(data, parentId = null) {
    // 过滤出当前父ID下的所有子节点,再递归给每个子节点找它的子节点
    return data
        .filter(task => task.ParentID === parentId)
        .map(task => ({
            ...task,
            subtasks: buildHierarchy(data, task.id)
        }));
}

const result = buildHierarchy(data);
console.log(JSON.stringify(result, null, 2));

两种方案怎么选?

  • 映射表方案:性能更优,适合数据量大的场景,比如有成百上千条待办的情况。
  • 递归查找方案:代码更短更容易理解,但每次递归都要过滤整个数组,时间复杂度是O(n²),数据量小的时候用起来特别顺手。

Next.js项目里的最佳实践

  1. 数据处理时机:尽量在服务端或者请求回调里处理层级转换,比如在getServerSideProps、getStaticProps,或者SWR/React Query的fetcher函数里处理,不要在组件渲染时重复执行,避免不必要的性能损耗。
  2. 缓存处理后的数据:如果数据不会频繁变化,用useMemo缓存处理后的层级数据,防止组件重渲染时重复计算:
    import { useMemo } from 'react';
    
    // 假设rawData是从接口获取的平级数据
    const hierarchicalData = useMemo(() => buildHierarchy(rawData), [rawData]);
    
  3. 类型安全(TypeScript项目):可以给待办事项定义接口,让代码更健壮:
    interface Todo {
        id: number;
        Name: string;
        ParentID: number | null;
    }
    
    interface HierarchicalTodo extends Todo {
        subtasks: HierarchicalTodo[];
    }
    

用上面的方案处理你给出的示例数据,都会完美生成你想要的层级结构,而且后续不管嵌套多少层,都能自动处理~

备注:内容来源于stack exchange,提问作者paipai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 12:39:32