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

JS深度嵌套数据过滤:返回父级/直接子项的实现方案问询

深度嵌套数据过滤:保留父级+目标节点的最优实现方案

嘿,我完全懂处理这种深度嵌套数据时的头疼感——尤其是还要对接不同场景的筛选器,刚开始确实容易摸不着头绪。咱们一步步拆解这个问题,从核心思路到具体实现,再到适配不同场景的技巧,都给你理清楚。

核心思路先明确

首先得把需求拆透:你要的是筛选出符合条件的节点,同时保留这些节点的所有父级(这样在UI里能展开看到目标节点),并且保留目标节点的直接子项(如果子项不需要额外筛选的话)。

举个直观的例子:假设你的数据是树形结构,当某个孙节点符合筛选条件,那它的父节点、祖父节点都要保留,同时这个孙节点的直接子节点(如果有的话)也得留下——不管子节点是否符合条件。

基础实现:递归法(中小数据量首选)

递归是处理嵌套结构最直观的方式,代码简洁易懂,适合数据量不大的场景。咱们直接上代码,带详细注释:

// 通用过滤函数:支持自定义筛选条件、自定义子节点字段名
function filterNestedTree(nodes, filterCondition, childrenKey = 'children') {
  return nodes.reduce((result, currentNode) => {
    // 递归处理当前节点的子节点
    const filteredChildren = currentNode[childrenKey] 
      ? filterNestedTree(currentNode[childrenKey], filterCondition, childrenKey) 
      : [];

    // 判断是否需要保留当前节点:要么自身符合条件,要么子节点里有符合条件的(需要保留父级)
    const shouldKeep = filterCondition(currentNode) || filteredChildren.length > 0;

    if (shouldKeep) {
      // 复制原节点(避免修改原始数据),替换子节点为过滤后的结果
      const keptNode = { ...currentNode };
      if (currentNode[childrenKey]) {
        // 如果当前节点本身符合条件,直接保留所有直接子项;否则用过滤后的子节点
        keptNode[childrenKey] = filterCondition(currentNode) ? [...currentNode[childrenKey]] : filteredChildren;
      }
      result.push(keptNode);
    }

    return result;
  }, []);
}

怎么用?

假设你的REST返回的数据是这样的:

const apiData = [
  {
    id: 1,
    name: "部门A",
    children: [
      { id: 11, name: "小组A1", children: [{ id: 111, name: "张三", role: "前端" }] },
      { id: 12, name: "小组A2", children: [{ id: 121, name: "李四", role: "后端" }] }
    ]
  },
  {
    id: 2,
    name: "部门B",
    children: [{ id: 21, name: "王五", role: "前端" }]
  }
];

如果要筛选所有role === '前端'的节点,同时保留父级和直接子项:

// 定义筛选条件
const isFrontend = node => node.role === '前端';
// 执行过滤
const filteredResult = filterNestedTree(apiData, isFrontend);

得到的结果会是:

[
  {
    id: 1,
    name: "部门A",
    children: [
      { id: 11, name: "小组A1", children: [{ id: 111, name: "张三", role: "前端" }] }
    ]
  },
  {
    id: 2,
    name: "部门B",
    children: [{ id: 21, name: "王五", role: "前端" }]
  }
]

大数据量优化:迭代+标记法

如果你的数据量特别大(比如上千个节点),递归可能会导致栈溢出。这时候可以用先标记所有需要保留的节点,再重构树形结构的方式:

function filterLargeNestedTree(nodes, filterCondition, childrenKey = 'children') {
  const keepNodeIds = new Set();

  // 第一步:深度优先遍历,标记所有需要保留的节点(自身符合条件,或有后代符合)
  function markNodes(node) {
    let hasMatchingDescendant = false;
    // 先处理子节点
    if (node[childrenKey]) {
      for (const child of node[childrenKey]) {
        if (markNodes(child)) {
          hasMatchingDescendant = true;
        }
      }
    }
    // 判断当前节点是否需要保留
    const shouldKeep = filterCondition(node) || hasMatchingDescendant;
    if (shouldKeep) {
      keepNodeIds.add(node.id); // 假设每个节点有唯一id,没有的话可以用对象引用
    }
    return shouldKeep;
  }

  // 标记所有节点
  nodes.forEach(node => markNodes(node));

  // 第二步:根据标记重构树形结构
  function buildTree(treeNodes) {
    return treeNodes.reduce((result, node) => {
      if (keepNodeIds.has(node.id)) {
        const keptNode = { ...node };
        if (node[childrenKey]) {
          keptNode[childrenKey] = buildTree(node[childrenKey]);
        }
        result.push(keptNode);
      }
      return result;
    }, []);
  }

  return buildTree(nodes);
}

适配不同场景&筛选器

你的需求里提到要适配不同场景和下拉框筛选器,这里给两个实用技巧:

1. 动态切换筛选条件

把不同的筛选逻辑做成一个映射表,下拉框选中时直接取对应的条件即可:

// 筛选条件映射表,对应下拉框的选项值
const filterOptions = {
  'frontend': node => node.role === '前端',
  'backend': node => node.role === '后端',
  'dept-a': node => node.name.includes('部门A'),
  'name-contains-张': node => node.name?.includes('张')
};

// 当下拉框选中"frontend"时:
const selectedFilter = filterOptions['frontend'];
const result = filterNestedTree(apiData, selectedFilter);

2. 适配不同的节点结构

如果REST返回的数据子节点字段不是children(比如是items或subNodes),只需要调用函数时传入第三个参数:

// 假设子节点字段是items
const result = filterNestedTree(apiData, isFrontend, 'items');

关键注意点

  • 不要修改原始数据:始终复制节点后再修改,避免影响其他地方使用数据
  • 处理空值:比如节点可能没有子节点、字段可能不存在,要加可选链(?.)或判断
  • 性能考量:递归适合中小数据,大数据用迭代标记法;如果是超大量数据,可能需要后端配合做部分筛选

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:08:46