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

如何用JavaScript的reduce方法处理缩进路径树生成完整路径组合?

用JavaScript的reduce处理缩进树形路径问题

我尝试用JavaScript的reduce方法处理带制表符缩进的树形路径字符串(输入缩进格式完全正确),知道回溯法能实现,但想试试reduce。当前代码输出重复内容,达不到预期,求修正。

给定输入:

/wp-content/
    /uploads
    /plugins/
        /akismet/
    /themes/
        /twentyeleven/
            /colors/

期望输出(包含所有中间路径组合):

/wp-content/
/wp-content/uploads
/wp-content/plugins/
/wp-content/plugins/akismet/
/wp-content/themes/
/wp-content/themes/twentyeleven/
/wp-content/themes/twentyeleven/colors

当前代码输出(重复内容):

/wp-admin/wp-content/plugins/akismet/themes/twentyeleven/colors 
/wp-admin/wp-content/plugins/akismet/themes/twentyeleven/images 
/wp-admin/wp-content/uploads 
/wp-admin/wp-content/plugins/akismet/themes/twentyeleven/colors 
/wp-admin/wp-content/plugins/akismet/themes/twentyeleven/images 
/wp-admin/wp-content/uploads 

原代码

rm = (s, ch='\t') => s?.replaceAll(ch,'')
count = (s, ch='\t') => s?.match(new RegExp(ch,'g'))?.length
wrapper = (arr, fun, start) => arr.reduce(fun, start)

function fn(acc, curr, i, self){
  x = count(curr) 
    y = count(self[i+1])
  curr = rm(curr)
  acc = rm(acc)
  selfi = rm(self[i+1]) 
  if(!selfi) return acc
  
  if(curr.at(-1) === '/' && acc.at(0) === '/') {
     curr = curr.slice(0,-1)
  } // ends and start with /
    if(x===y){
            console.log(acc+curr)
      return acc
    } else { 
      idx = self.indexOf(self.slice(0,i+1).filter(k => count(k) === x)[0]) 
      if(!idx) idx = -1
      wrapper(self.slice(i,idx), fn, acc) 
      return acc+curr
  }
}

wrapper(ar, fn, '/wp-admin')

问题分析

原代码的核心问题:

  1. 变量未声明(x、y、curr等均为全局变量),reduce迭代时变量被污染,导致重复输出
  2. 缩进层级判断逻辑混乱,错误使用self.indexOf定位父节点,递归范围完全错误
  3. 没有维护层级栈追踪父路径,路径拼接逻辑无法匹配树形结构

修正后的代码

思路:用reduce维护一个层级栈,每个元素存储对应层级的完整路径。根据当前行的缩进层级找到父节点,拼接路径后加入结果集,同时更新层级栈。

// 移除字符串中的制表符
const rm = (s, ch = '\t') => s?.replaceAll(ch, '') ?? '';
// 统计字符串中的制表符数量(即当前路径的层级)
const countIndent = (s, ch = '\t') => s?.match(new RegExp(ch, 'g'))?.length ?? 0;

function generateFullPaths(lines, root = '') {
  const result = [];
  // 层级栈:存储{ indent: 层级数, fullPath: 对应层级的完整路径 }
  const levelStack = [];

  lines.reduce((_, currLine) => {
    const currIndent = countIndent(currLine);
    const currPath = rm(currLine);

    // 找到当前层级的父路径
    let parentPath = root;
    for (let i = levelStack.length - 1; i >= 0; i--) {
      if (levelStack[i].indent < currIndent) {
        parentPath = levelStack[i].fullPath;
        break;
      }
    }

    // 处理斜杠重复问题,拼接完整路径
    let fullPath;
    if (parentPath.endsWith('/') && currPath.startsWith('/')) {
      fullPath = parentPath + currPath.slice(1);
    } else if (!parentPath.endsWith('/') && !currPath.startsWith('/')) {
      fullPath = parentPath + '/' + currPath;
    } else {
      fullPath = parentPath + currPath;
    }

    // 存入结果集
    result.push(fullPath);
    // 更新层级栈:移除所有层级>=当前层级的元素,加入当前层级记录
    while (levelStack.length > 0 && levelStack[levelStack.length - 1].indent >= currIndent) {
      levelStack.pop();
    }
    levelStack.push({ indent: currIndent, fullPath });

    return _;
  }, null);

  return result;
}

// 测试输入(注意制表符替换为\t)
const inputLines = [
  '/wp-content/',
  '\t/uploads',
  '\t/plugins/',
  '\t\t/akismet/',
  '\t/themes/',
  '\t\t/twentyeleven/',
  '\t\t\t/colors/'
];

// 生成并输出路径
const paths = generateFullPaths(inputLines);
paths.forEach(path => console.log(path));

运行结果

执行后会输出预期的所有路径:

/wp-content/
/wp-content/uploads
/wp-content/plugins/
/wp-content/plugins/akismet/
/wp-content/themes/
/wp-content/themes/twentyeleven/
/wp-content/themes/twentyeleven/colors

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:15:52