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

如何从未知深度嵌套数组中移除不匹配的无子节点元素

嵌套数组递归过滤问题

需求规则

需要基于指定匹配值数组,从嵌套数组中移除不符合要求的元素,规则如下:

  • 数组嵌套深度未知,元素可包含嵌套的children子节点
  • 仅移除不存在children子节点的叶子元素
  • 元素不在匹配数组中时才执行移除操作

原有问题代码

import * as lodash from "https://cdn.skypack.dev/lodash@4.17.21";

let filterRecursively = (arr, match) => {
  // 递归查找最深层数组
  arr.forEach(el => {
      arr = el.children ? filterRecursively(el.children, match) : arr
  });

  // 最深层执行元素过滤
  if (arr[0] && arr[0].children === undefined) {
    return _.filter(arr, (item) => {
        return match.includes(item.name)
    })
  } else { // 非最深层直接返回原数组
    return arr
  }
}

let arr = [
  {
    'name': 'John',
    'children': [
      {
        'name': 'John',
        'children': [
          { 'name': 'John' },
          { 'name': 'Jane' },
          { 'name': 'Joe' }
        ]
      }]
  }, {
    'name': 'Jeff',
    'children': [
      {
        'name': 'Joe',
        'children': [
          { 'name': 'Jill' },
          { 'name': 'Jeff' },
          { 'name': 'Joe' }
        ]
      }]
  }];

let match = ['John', 'Joe'];
let result = filterRecursively(arr, match);

console.log(result);

预期输出

[
   {
     'name': 'John',
     'children': [
       {
         'name': 'John',
         'children': [
           { 'name': 'John' },
           { 'name': 'Joe' }
         ]
       }]
   }, {
     'name': 'Jeff',
     'children': [
       {
         'name': 'Joe',
         'children': [
           { 'name': 'Joe' }
         ]
       }]
   }];

实际错误输出

[
    {
        "name": "Joe"
    }
]

错误原因

原有递归逻辑存在两个核心问题:

  1. 遍历当前层元素时,反复将整个当前层数组arr赋值为子节点递归的返回值,没有为每个元素单独更新处理后的children属性,上层嵌套结构直接被覆盖丢弃
  2. 最深层判断逻辑有漏洞,没有逐层保留非叶子节点,最终只会返回最后一次递归得到的某一组深层叶子节点

修正方案

按照规则调整递归逻辑:遍历当前数组时,优先递归处理每个元素的子节点,非叶子节点直接保留,仅对叶子节点做匹配值过滤即可,不需要额外依赖lodash:

let filterRecursively = (arr, match) => {
  return arr.filter(item => {
    // 存在子节点时先递归处理子节点
    if (Array.isArray(item.children) && item.children.length) {
      item.children = filterRecursively(item.children, match);
      // 非叶子节点无论name是否匹配都保留
      return true;
    }
    // 叶子节点仅保留name在匹配列表中的项
    return match.includes(item.name);
  })
}

运行上述修正后的代码,即可保留完整嵌套结构,得到符合预期的输出结果。


内容的提问来源于stack exchange,提问作者Morten Najbjerg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 09:24:24