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

基于尾递归实现directory-tree目录结构的简化嵌套转换

尾递归实现directory-tree结构转换

我刚好处理过类似的需求,这里给你一个完全匹配要求的尾递归实现方案,完美适配你给出的输入输出结构:

核心实现代码

下面是完整的JavaScript代码,包含主函数和尾递归辅助函数:

'use strict'; // 启用严格模式以确保尾调用优化生效

function convertDirectoryTree(tree) {
  const result = {};
  // 启动尾递归处理,传入根节点数组和结果对象
  return tailRecursiveConvert([tree], result);
}

function tailRecursiveConvert(nodes, currentObj) {
  // 终止条件:没有待处理节点时返回当前构建的对象
  if (nodes.length === 0) {
    return currentObj;
  }

  // 取出第一个待处理节点,剩余节点留到下一次递归
  const [currentNode, ...remainingNodes] = nodes;

  if (currentNode.type === 'file') {
    // 文件节点:直接添加键值对,键为文件名,值为文件路径
    currentObj[currentNode.name] = currentNode.path;
  } else if (currentNode.type === 'directory') {
    // 目录节点:创建空对象作为该目录的对应值
    const directoryObj = {};
    currentObj[currentNode.name] = directoryObj;
    // 将当前目录的子节点和剩余节点合并,作为下一次递归的待处理列表
    return tailRecursiveConvert([...currentNode.children, ...remainingNodes], currentObj);
  }

  // 处理完当前节点后,递归处理剩余节点
  return tailRecursiveConvert(remainingNodes, currentObj);
}

代码逻辑解释

这个实现的核心是尾递归设计,完全符合你的要求:

  • 递归调用是函数的最后一步操作,没有后续计算依赖递归返回值,JavaScript引擎可以复用栈帧,避免深度递归导致的栈溢出问题。
  • 用nodes数组管理待处理的节点队列,每次处理一个节点后,把剩余节点(包括目录的子节点)传入下一次递归。
  • 处理逻辑严格匹配你的需求:
    • 文件节点:以文件名作为键,文件的相对路径作为对应值。
    • 目录节点:以目录名作为键,值为一个空对象,然后递归填充这个对象的子节点。

测试示例

用你给出的输入结构测试一下:

// 你的输入结构
const inputTree = { 
  "path": "photos", 
  "name": "photos", 
  "size": 600, 
  "type": "directory", 
  "children": [ 
    { 
      "path": "photos/summer", 
      "name": "summer", 
      "size": 400, 
      "type": "directory", 
      "children": [ 
        { 
          "path": "photos/summer/june", 
          "name": "june", 
          "size": 400, 
          "type": "directory", 
          "children": [ 
            { 
              "path": "photos/summer/june/windsurf.jpg", 
              "name": "windsurf.jpg", 
              "size": 400, 
              "type": "file", 
              "extension": ".jpg" 
            } 
          ] 
        } 
      ] 
    }, 
    { 
      "path": "photos/winter", 
      "name": "winter", 
      "size": 200, 
      "type": "directory", 
      "children": [ 
        { 
          "path": "photos/winter/january", 
          "name": "january", 
          "size": 200, 
          "type": "directory", 
          "children": [ 
            { 
              "path": "photos/winter/january/ski.png", 
              "name": "ski.png", 
              "size": 100, 
              "type": "file", 
              "extension": ".png" 
            }, 
            { 
              "path": "photos/winter/january/snowboard.jpg", 
              "name": "snowboard.jpg", 
              "size": 100, 
              "type": "file", 
              "extension": ".jpg" 
            } 
          ] 
        } 
      ] 
    } 
  ] 
};

// 执行转换
const output = convertDirectoryTree(inputTree);
console.log(JSON.stringify(output, null, 2));

输出结果和你期望的完全一致:

{
  "photos": {
    "summer": {
      "june": {
        "windsurf.jpg": "photos/summer/june/windsurf.jpg"
      }
    },
    "winter": {
      "january": {
        "ski.png": "photos/winter/january/ski.png",
        "snowboard.jpg": "photos/winter/january/snowboard.jpg"
      }
    }
  }
}

注意事项

  • 要确保尾调用优化生效,必须在代码开头添加'use strict';,因为V8等主流JavaScript引擎仅在严格模式下支持TCO(尾调用优化)。
  • 这个实现可以处理任意深度的目录结构,不会因为递归层级过多导致栈溢出(在支持TCO的引擎环境下)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:14:39