如何从嵌套分类数据中提取并展平指定子节点

来源:菜鸟站长作者:菲律宾程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《如何从嵌套分类数据中提取并展平指定子节点》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何从嵌套分类数据中提取并展平指定子节点》有用,将其分享出去将是对创作者最好的鼓励。

嵌套分类数据通常以树形结构存储,每个节点可能包含自身的属性信息和子节点数组,实际开发中经常需要从中提取符合特定条件的子节点,并将这些子节点展平为单一的列表结构,方便进行后续的数据渲染、统计或者接口返回。

如何从嵌套分类数据中提取并展平指定子节点

嵌套分类数据的常见结构

典型的嵌套分类数据格式如下,每个节点包含id、name、type等属性,同时可能有children字段存储子节点:

// 示例嵌套分类数据
const categoryData = [
  {
    id: 1,
    name: '数码产品',
    type: 'parent',
    children: [
      {
        id: 11,
        name: '手机',
        type: 'child',
        children: [
          { id: 111, name: '智能手机', type: 'leaf' },
          { id: 112, name: '功能手机', type: 'leaf' }
        ]
      },
      {
        id: 12,
        name: '电脑',
        type: 'child',
        children: [
          { id: 121, name: '笔记本电脑', type: 'leaf' },
          { id: 122, name: '台式电脑', type: 'leaf' }
        ]
      }
    ]
  },
  {
    id: 2,
    name: '家居用品',
    type: 'parent',
    children: [
      { id: 21, name: '家具', type: 'leaf' },
      { id: 22, name: '家纺', type: 'leaf' }
    ]
  }
];

递归方式提取并展平子节点

递归是最直观的处理树形结构的方式,我们可以定义一个递归函数,遍历每个节点,判断是否符合提取条件,符合则加入结果数组,再继续遍历其子节点。

假设我们需要提取所有type为leaf的子节点,实现代码如下:

/**
 * 递归提取嵌套分类数据中的指定子节点并展平
 * @param {Array} data 嵌套分类数据
 * @param {Function} filterFn 筛选条件函数,返回true表示需要提取该节点
 * @returns {Array} 展平后的节点数组
 */
function flattenSpecifiedNodes(data, filterFn) {
  const result = [];
  // 递归遍历函数
  function traverse(nodes) {
    if (!Array.isArray(nodes)) return;
    nodes.forEach(node => {
      // 判断当前节点是否符合筛选条件
      if (filterFn(node)) {
        result.push(node);
      }
      // 如果存在子节点,继续递归遍历
      if (node.children && node.children.length > 0) {
        traverse(node.children);
      }
    });
  }
  traverse(data);
  return result;
}

// 调用函数提取type为leaf的节点
const leafNodes = flattenSpecifiedNodes(categoryData, node => node.type === 'leaf');
console.log(leafNodes);
// 输出结果包含111、112、121、122、21、22共6个叶子节点

迭代方式实现节点提取与展平

递归方式在嵌套层级过深时可能出现栈溢出问题,此时可以使用迭代方式,通过栈或队列来维护待遍历的节点。

同样以提取type为leaf的节点为例,迭代实现代码如下:

/**
 * 迭代方式提取嵌套分类数据中的指定子节点并展平
 * @param {Array} data 嵌套分类数据
 * @param {Function} filterFn 筛选条件函数
 * @returns {Array} 展平后的节点数组
 */
function flattenSpecifiedNodesIteratively(data, filterFn) {
  const result = [];
  // 使用栈存储待处理的节点,初始放入所有根节点
  const stack = [...data];
  while (stack.length > 0) {
    // 取出栈顶节点
    const currentNode = stack.pop();
    // 判断是否符合筛选条件
    if (filterFn(currentNode)) {
      result.push(currentNode);
    }
    // 如果存在子节点,将子节点放入栈中待处理
    if (currentNode.children && Array.isArray(currentNode.children)) {
      // 使用扩展运算符将子节点加入栈,也可以用push循环加入
      stack.push(...currentNode.children);
    }
  }
  return result;
}

// 调用迭代函数提取叶子节点
const leafNodesIterative = flattenSpecifiedNodesIteratively(categoryData, node => node.type === 'leaf');
console.log(leafNodesIterative);

两种方式的对比

我们可以通过表格对比两种实现方式的特点:

实现方式优点缺点适用场景
递归方式代码逻辑直观,符合树形结构的遍历思维,实现简单嵌套层级过深时可能导致调用栈溢出嵌套层级较浅,数据量不大的场景
迭代方式没有栈溢出风险,性能更稳定代码逻辑相对复杂,需要手动维护遍历队列嵌套层级深,数据量大的场景

实际场景中的扩展用法

上述示例的筛选条件是固定的,实际开发中我们可以灵活调整filterFn函数来实现不同的提取需求:

  • 提取指定id的子节点:node => node.id === 12
  • 提取名称包含特定关键词的节点:node => node.name.includes('手机')
  • 提取所有非叶子节点:node => node.type !== 'leaf'

如果需要提取的子节点还要保留部分父节点信息,可以在筛选时给节点添加额外的属性,再推入结果数组,比如记录父节点名称:

function flattenWithParentInfo(data, filterFn) {
  const result = [];
  function traverse(nodes, parentName = '') {
    nodes.forEach(node => {
      // 给符合条件的节点添加父节点名称属性
      if (filterFn(node)) {
        const newNode = { ...node, parentName };
        result.push(newNode);
      }
      // 递归子节点时传入当前节点名称作为父节点名称
      if (node.children) {
        traverse(node.children, node.name);
      }
    });
  }
  traverse(data);
  return result;
}

// 提取叶子节点并附带父节点名称
const leafWithParent = flattenWithParentInfo(categoryData, node => node.type === 'leaf');
console.log(leafWithParent[0].parentName); // 输出 手机

在处理嵌套分类数据时,根据实际的数据规模和嵌套深度选择合适的遍历方式,就能高效完成指定子节点的提取和展平操作。

嵌套分类数据子节点提取数据展平递归遍历修改时间:2026-07-16 03:45:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。