如何从未知深度嵌套数组中移除不匹配的无子节点元素
嵌套数组递归过滤问题
需求规则
需要基于指定匹配值数组,从嵌套数组中移除不符合要求的元素,规则如下:
- 数组嵌套深度未知,元素可包含嵌套的
children子节点 - 仅移除不存在
children子节点的叶子元素 - 元素不在匹配数组中时才执行移除操作
原有问题代码
import * as lodash from "https://cdn.skypack.dev/lodash@4.17.21"; let filterRecursively = (arr, match) => { // 递归查找最深层数组 arr.forEach(el => { arr = el.children ? filterRecursively(el.children, match) : arr }); // 最深层执行元素过滤 if (arr[0] && arr[0].children === undefined) { return _.filter(arr, (item) => { return match.includes(item.name) }) } else { // 非最深层直接返回原数组 return arr } } let arr = [ { 'name': 'John', 'children': [ { 'name': 'John', 'children': [ { 'name': 'John' }, { 'name': 'Jane' }, { 'name': 'Joe' } ] }] }, { 'name': 'Jeff', 'children': [ { 'name': 'Joe', 'children': [ { 'name': 'Jill' }, { 'name': 'Jeff' }, { 'name': 'Joe' } ] }] }]; let match = ['John', 'Joe']; let result = filterRecursively(arr, match); console.log(result);
预期输出
[ { 'name': 'John', 'children': [ { 'name': 'John', 'children': [ { 'name': 'John' }, { 'name': 'Joe' } ] }] }, { 'name': 'Jeff', 'children': [ { 'name': 'Joe', 'children': [ { 'name': 'Joe' } ] }] }];
实际错误输出
[ { "name": "Joe" } ]
错误原因
原有递归逻辑存在两个核心问题:
- 遍历当前层元素时,反复将整个当前层数组
arr赋值为子节点递归的返回值,没有为每个元素单独更新处理后的children属性,上层嵌套结构直接被覆盖丢弃 - 最深层判断逻辑有漏洞,没有逐层保留非叶子节点,最终只会返回最后一次递归得到的某一组深层叶子节点
修正方案
按照规则调整递归逻辑:遍历当前数组时,优先递归处理每个元素的子节点,非叶子节点直接保留,仅对叶子节点做匹配值过滤即可,不需要额外依赖lodash:
let filterRecursively = (arr, match) => { return arr.filter(item => { // 存在子节点时先递归处理子节点 if (Array.isArray(item.children) && item.children.length) { item.children = filterRecursively(item.children, match); // 非叶子节点无论name是否匹配都保留 return true; } // 叶子节点仅保留name在匹配列表中的项 return match.includes(item.name); }) }
运行上述修正后的代码,即可保留完整嵌套结构,得到符合预期的输出结果。
内容的提问来源于stack exchange,提问作者Morten Najbjerg
相关产品推荐
相关产品推荐

