如何根据uniqueId属性从嵌套对象中提取匹配指定ID集合的节点
嵌套对象按目标ID提取链路的实现
核心实现逻辑
不用逐次遍历ID数组查找路径,直接做一次深度递归遍历即可,运行效率更高:
- 把待匹配的uniqueId数组转成
Set,实现常数级的匹配查找,避免数组遍历的性能损耗 - 递归从根节点开始向下遍历,每个节点做三类判断:
- 如果当前节点自身的
uniqueId在目标集合中,直接保留整个节点,不再继续拆分它的子节点 - 如果当前节点的子节点经过递归处理后存在需要保留的内容,就保留当前节点(包括它自身的所有原有属性,比如父级的
uniqueId),只把收集到的有效子节点拼到当前节点上 - 如果当前节点既不在目标集合,下方也没有需要保留的有效子节点,直接丢弃整个分支
- 如果当前节点自身的
完整可运行代码
// 原对象结构 const obj = { a: { uniqueId: 'u_a', }, groupA: { uniqueId: 'u_groupA', nested: { b: { uniqueId: 'u_b', }, c: { uniqueId: 'u_c', }, anotherGroup: { uniqueId: 'u_anotherGroup', nested: { d: { uniqueId: 'u_d', }, e: { uniqueId: 'u_e', }, } }, } }, }; /** * 按目标uniqueId提取有效链路 * @param {object} source 原始嵌套对象 * @param {string[]} targetIds 需要匹配的uniqueId列表 * @returns {object} 裁剪后的结果对象 */ function pickByUniqueId(source, targetIds) { const targetSet = new Set(targetIds); function traverseNode(node) { // 处理非对象的基础类型节点 if (typeof node !== 'object' || node === null) { return targetSet.has(node) ? node : undefined; } // 节点本身命中目标,直接返回完整节点 if (targetSet.has(node.uniqueId)) { return node; } // 遍历子节点,收集需要保留的内容 const keptNodes = {}; for (const [key, value] of Object.entries(node)) { const processed = traverseNode(value); if (processed !== undefined) { keptNodes[key] = processed; } } // 存在有效子节点时,保留当前节点自身属性+有效子节点 if (Object.keys(keptNodes).length > 0) { return { ...node, ...keptNodes }; } // 无有效内容时丢弃当前节点 return undefined; } return traverseNode(source) ?? {}; }
场景匹配验证
把提到的几个场景代入函数运行,输出完全和预期一致:
- 传入
pickByUniqueId(obj, ['u_a']):返回结构为{ a: { uniqueId: 'u_a' } },无冗余分支 - 传入
pickByUniqueId(obj, ['u_b']):自动生成groupA -> nested -> b的完整链路,保留groupA的uniqueId: 'u_groupA'属性,同时剔除同层级的c、anotherGroup等无关节点 - 传入
pickByUniqueId(obj, ['u_a', 'u_b', 'u_d']):自动合并两个目标节点的公共父链路,不会重复生成冗余层级,自动剔除c、e这类没有匹配到目标的分支
实现细节说明:处理父链路节点时,是先拷贝当前节点的所有原有属性,再覆盖为收集到的有效子节点,不会出现只保留路径键名、丢失父节点自身属性(比如分组的
uniqueId)的问题。
内容的提问来源于stack exchange,提问作者Mohammed Saber Mohammed
相关产品推荐
相关产品推荐

