You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript嵌套数组过滤问题:筛选指定数组中的叶子节点key

实现嵌套数组的终端节点筛选逻辑

我来帮你解决这个嵌套数组的筛选问题,咱们一步步拆解思路并实现代码:

问题明确

你有一个多层嵌套的节点数组 arr,以及一个包含目标key的数组 arr2 = [1, 2, 3, 4, 8],需要筛选出arr2中那些没有任何后代节点的key也在arr2里的节点,最终得到结果 arr3 = [4, 8]。简单来说,就是要保留arr2里的「终端节点」——它们的子节点(包括所有后代)都不在目标列表中。

实现思路

  1. 建立节点映射:先遍历嵌套数组,把每个节点用key作为索引存到Map里,方便后续快速查找任意key对应的节点。
  2. 递归检查后代:对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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:34:39