多级嵌套数组过滤含Gold标记的Case节点并保留父层级
解决方案:过滤嵌套数组中指定flag的Case节点并保留父级结构
需求明确
需要过滤出所有flag值为Gold的Case类型节点,同时保留这些节点所在的完整父级路径(Group、Model、Project层级),且仅Model或Project的直接子节点可能是带flag的Case。
之前方法的问题
1. Filter方法的问题
- 直接修改原数组的
cases属性,污染原数据且不符合纯函数设计原则。 - 逻辑错误:仅对
Model/Project的cases直接过滤,未递归处理Project的子Project节点,导致深层Case(如示例中的Case2)无法被正确筛选。 - 未利用
filter的返回值,递归调用时未更新节点的cases列表。
2. Reduce方法的问题
- 未区分节点类型:对于Group/Model/Project这类父节点,仅在子节点过滤结果非空时才保留,但未正确保留父节点的完整属性(如
type)。 - 递归逻辑有误:未明确Case节点与父节点的处理边界,导致递归流程混乱,甚至出现逻辑上的无效循环。
正确实现方案
通过递归函数遍历节点,根据类型差异化处理:
- Case类型:仅当
flag匹配目标值时保留节点。 - Group/Model/Project类型:递归处理子
cases,若过滤后的子节点列表非空,则保留当前父节点(复制属性并替换cases为过滤后的列表),否则丢弃当前节点。
代码实现(TypeScript)
private getFilteredList(models: any[], targetFlag: string): any[] { return models.reduce((result, item) => { // 处理Case节点:判断flag是否匹配 if (item.type === 'Case') { if (item.flag === targetFlag) { result.push({ ...item }); // 复制节点避免修改原数据 } return result; } // 处理父级节点:递归过滤子cases const filteredChildren = this.getFilteredList(item.cases || [], targetFlag); if (filteredChildren.length > 0) { result.push({ ...item, cases: filteredChildren }); } return result; }, []); }
代码说明
- 纯函数设计:不修改原数组,通过对象复制返回新的过滤结果,避免原数据被污染。
- 类型精准处理:明确区分Case节点与父级节点的逻辑,确保只有符合条件的Case被保留,同时完整保留其路径上的父节点。
- 自然终止递归:当Case节点不匹配、子节点过滤后为空时,自动终止对应分支的递归,避免无效计算。
测试验证
调用示例:
const filteredResult = this.getFilteredList(models, 'Gold');
输出结构与预期完全一致:
Group1 ...Model1 { Case1 } ...Model2 ...Project1 ...Project2 { Case2 } { Case4 } Group2 ...Model3 { Case5 }
内容的提问来源于stack exchange,提问作者Dennis R
相关产品推荐
相关产品推荐

