如何用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')
问题分析
原代码的核心问题:
- 变量未声明(
x、y、curr等均为全局变量),reduce迭代时变量被污染,导致重复输出 - 缩进层级判断逻辑混乱,错误使用
self.indexOf定位父节点,递归范围完全错误 - 没有维护层级栈追踪父路径,路径拼接逻辑无法匹配树形结构
修正后的代码
思路:用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
相关产品推荐
相关产品推荐

