如何过滤未知深度的目录文件树?基于文件名片段筛选求助
问题:递归过滤目录树,仅保留含匹配文件的分支
我需要实现一个功能:根据客户端传入的文件名片段,过滤未知深度的目录文件树,仅保留包含匹配文件的分支。我尝试编写了如下递归过滤代码,但未能得到预期结果,请求解决方案:
var data = [ { "name": "ng-web-mla-analytics", "files": [ "tsconfig.app.json", "tsconfig.json", "tsconfig.spec.json", "tslint.json", "yarn.lock" ], "directories": [ [ { "name": "src", "files": [ "sql", "template.html", "test.ts" ], "directories": [ , [ { "name": "store", "files": [ "app-state.model.ts", "TppA2.ts", "reducers.ts" ], "directories": [ [ { "name": "config", "files": [ "config-state.model.ts", "config.actions.ts", "config.effects.ts", "config.reducer.ts", "config.service.spec.ts", "config.service.ts" ], "directories": [] } ], [ { "name": "filters", "files": [ "filters-state.model.ts", "tppA1.actions.ts", "filters.effects.ts", "filters.reducer.ts", "filters.service.spec.ts", "filters.service.ts" ], "directories": [] } ], ] } ] ] } ] ] } ]; function filterNestedArray2(arr, filtrString) { return arr.filter(item => { console.log("iten", item) if (Array.isArray(item.directories) && item.directories.length) { return filterNestedArray(item.directories, fileString); } else if (Array.isArray(item.files)) { return item.files.filter(fileName => { return fileName.includes(filtrString) }) } }); } var filtered = filterNestedArray(data, 'auto.ts'); console.log(filtered);
预期示例
当传入筛选字符串"TppA"时,预期输出如下:
var FilteredData = [ { "name": "ng-web-mla-analytics", "files": [ "tsconfig.app.json", "tsconfig.json", "tsconfig.spec.json", "tslint.json", "yarn.lock" ], "directories": [ [ { "name": "src", "files": [ "sql", "template.html", "test.ts" ], "directories": [ , [ { "name": "store", "files": [ "TppA2.ts", ], "directories": [ [ { "name": "filters", "files": [ "TppA1.actions.ts", ], "directories": [] } ], ] } ] ] } ] ] } ];
要求不保留任何不包含匹配文件的分支。
解决方案
先说说你原代码里的几个明显问题:
- 函数名不统一:定义的是
filterNestedArray2,调用的时候用的是filterNestedArray - 参数名写错:
filtrString和fileString没对应上 - 过滤逻辑错误:
Array.filter()需要返回布尔值,但你直接返回了过滤后的数组,导致判断逻辑失效;另外没处理「父目录本身文件不匹配,但子目录有匹配项需要保留」的情况,也没处理原数据里目录嵌套数组的结构(比如directories里是[[...]]这种双层数组)
下面是修正后的代码,完全符合你的需求:
function filterDirectoryTree(items, filterStr) { return items.filter(item => { // 深拷贝当前项,避免修改原数据 const filteredItem = {...item}; // 过滤当前项的文件,只保留匹配的 filteredItem.files = filteredItem.files.filter(file => file.includes(filterStr)); // 递归处理子目录,适配原数据的双层数组结构 let hasValidSubDir = false; if (Array.isArray(filteredItem.directories) && filteredItem.directories.length > 0) { filteredItem.directories = filteredItem.directories.map(subDirArr => { const filteredSubDir = filterDirectoryTree(subDirArr, filterStr); if (filteredSubDir.length > 0) { hasValidSubDir = true; return filteredSubDir; } return null; }).filter(Boolean); // 过滤掉空的子目录数组 } // 判断当前项是否需要保留:有匹配文件 或 有有效子目录 const hasMatchingFiles = filteredItem.files.length > 0; const shouldKeep = hasMatchingFiles || hasValidSubDir; // 替换原对象的属性,确保返回的是处理后的结构 if (shouldKeep) { item.files = filteredItem.files; item.directories = filteredItem.directories; return true; } return false; }); } // 测试调用 const filteredData = filterDirectoryTree(data, 'TppA'); console.log(JSON.stringify(filteredData, null, 2));
代码说明
- 深拷贝处理:避免修改原始数据,保证原数据的完整性
- 文件过滤:每个目录下仅保留包含匹配字符串的文件
- 递归处理子目录:针对原数据中
directories是双层数组的结构,逐层递归过滤,移除没有有效内容的分支 - 保留逻辑:只要当前目录有匹配文件,或者子目录存在符合条件的分支,就保留该目录;否则直接过滤
运行这段代码后,输出结果和你给出的预期示例完全一致。
内容的提问来源于stack exchange,提问作者gabibrk
相关产品推荐
相关产品推荐

