JavaScript嵌套数组过滤问题:筛选指定数组中的叶子节点key
实现嵌套数组的终端节点筛选逻辑
我来帮你解决这个嵌套数组的筛选问题,咱们一步步拆解思路并实现代码:
问题明确
你有一个多层嵌套的节点数组 arr,以及一个包含目标key的数组 arr2 = [1, 2, 3, 4, 8],需要筛选出arr2中那些没有任何后代节点的key也在arr2里的节点,最终得到结果 arr3 = [4, 8]。简单来说,就是要保留arr2里的「终端节点」——它们的子节点(包括所有后代)都不在目标列表中。
实现思路
- 建立节点映射:先遍历嵌套数组,把每个节点用key作为索引存到Map里,方便后续快速查找任意key对应的节点。
- 递归检查后代:对arr2中的每个key,递归检查它的所有后代节点是否有出现在arr2中的。如果没有,就把这个key加入结果数组。
代码实现
// 原始嵌套数组 var arr = [ { key: 1, title: 'aa', children: [ { key: 2, title: 'bb', children: [ { key: 3, title: 'cc', children: [ { key: 5, title: 'ee', children: [ { key: 6, title: 'ff' }, { key: 7, title: 'gg' }, { key: 8, title: 'hh' } ] } ] }, { key: 4, title: 'dd', } ] } ] } ]; // 目标key数组 const arr2 = [1, 2, 3, 4, 8]; // 第一步:遍历嵌套数组,把所有节点存入Map,方便通过key快速获取节点 const nodeMap = new Map(); function traverseNode(node) { nodeMap.set(node.key, node); // 如果有子节点,递归遍历 if (node.children) { node.children.forEach(traverseNode); } } // 启动遍历 traverseNode(arr[0]); // 第二步:筛选符合条件的key const arr3 = arr2.filter(key => { const currentNode = nodeMap.get(key); // 递归函数:检查当前节点的所有后代是否有在arr2中的 function hasDescendantInTarget(node) { // 没有子节点,直接返回false if (!node.children) return false; // 检查子节点是否在arr2中,或者子节点的后代是否在arr2中 return node.children.some(child => { return arr2.includes(child.key) || hasDescendantInTarget(child); }); } // 如果当前节点没有后代在arr2中,就保留这个key return !hasDescendantInTarget(currentNode); }); console.log(arr3); // 输出:[4, 8]
代码解释
traverseNode函数递归遍历整个嵌套数组,把每个节点存入nodeMap,这样我们可以用nodeMap.get(key)快速拿到任意key对应的节点对象。hasDescendantInTarget是一个辅助递归函数,用来检查某个节点的所有后代(子节点、孙子节点等)是否有出现在arr2中的。- 最后用
Array.filter遍历arr2,只保留那些没有后代在arr2中的key,就是我们想要的arr3。
另一种实现思路(基于后代映射表)
如果你不想每次都递归检查,也可以先预先生成每个key的所有后代key列表,再做筛选:
function collectAllDescendants(node, descendantsMap = new Map()) { const childKeys = node.children ? node.children.map(c => c.key) : []; descendantsMap.set(node.key, [...childKeys]); if (node.children) { node.children.forEach(child => { const childDescendants = collectAllDescendants(child, descendantsMap); // 把子节点的后代合并到当前节点的后代列表中 descendantsMap.set(node.key, [...new Set([...descendantsMap.get(node.key), ...childDescendants.get(child.key)])]); }); } return descendantsMap; } // 生成后代映射表 const descendantsMap = collectAllDescendants(arr[0]); // 筛选逻辑 const arr3 = arr2.filter(key => { // 检查当前key的后代里有没有在arr2中的 return !descendantsMap.get(key).some(descKey => arr2.includes(descKey)); }); console.log(arr3); // 输出:[4, 8]
这个方法先把每个key的所有后代key都收集到Map里,后续筛选时直接查表判断,适合嵌套层级很深或者需要多次筛选的场景。
内容的提问来源于stack exchange,提问作者mxh861001
相关产品推荐
相关产品推荐

