JavaScript过滤嵌套对象数组 移除无P1风险项的父对象
实现嵌套数组双维度过滤
需求说明
现有对象数组结构满足以下特征:
- 数组每个元素是父对象,包含
title、rows两个属性 rows属性值为子对象数组,子对象包含risk属性,取值为P1、P2、P3等风险等级
需要实现的过滤规则:- 子项维度:仅保留
rows中risk值等于P1的行 - 父项维度:如果某个父对象下不存在任何
risk=P1的子行,直接剔除整个父对象
测试用的原始数据:
let data = [ { "title": "QA", "rows": [ { "risk": "P3", "Title": "Permission issue", } ] }, { "title": "Prod", "rows": [ { "risk": "P5", "Title": "Console log errors fix", }, { "risk": "P1", "Title": "Server is in hung state", } ] } ]
预期输出结果(无P1项的QA父对象被整体剔除):
[ { "title": "Prod", "rows": [ { "risk": "P1", "Title": "Server is in hung state", } ] } ]
原有代码问题
原有实现仅使用map遍历处理父对象:
let result = input.map((obj) => ({ ...obj, rows: obj.rows.filter((row) => row.risk === "P1"), }));
问题出在map的返回数组长度和原数组完全一致,即使某个父对象过滤后rows为空数组,依然会被保留在结果中,无法实现剔除空父对象的需求。
可行实现方案
方案1:filter+map 链式调用
逻辑拆为两步,先过滤掉不符合要求的父对象,再对保留的父对象做子项过滤,逻辑清晰易读:
const result = data // 先筛除所有不包含P1风险行的父对象 .filter(parent => parent.rows.some(row => row.risk === "P1")) // 对剩余父对象,仅保留rows里的P1风险行 .map(parent => ({ ...parent, rows: parent.rows.filter(row => row.risk === "P1") }))
方案2:reduce 单次遍历
只做一次数组遍历,过滤子项的同时判断是否需要保留父对象,遍历效率更高:
const result = data.reduce((res, parent) => { const p1Rows = parent.rows.filter(row => row.risk === "P1"); // 存在P1行才将处理后的父对象加入结果 if (p1Rows.length) { res.push({ ...parent, rows: p1Rows }) } return res; }, []);
两种方案运行后都能得到符合预期的输出结果,可根据代码风格偏好选择。
内容的提问来源于stack exchange,提问作者Aren Trot
相关产品推荐
相关产品推荐

