从嵌套的分类数据中提取指定ID的子节点并扁平化:JavaScript教程

从嵌套的分类数据中提取指定id的子节点并扁平化:javascript教程

从嵌套的分类数据中提取指定ID的子节点并扁平化:JavaScript教程

本文档详细介绍了如何使用JavaScript从深度嵌套的分类数据中提取特定ID的子节点,并将结果扁平化为一个数组。我们提供了一个高效的算法,避免了传统的循环结构,而是采用栈数据结构和条件判断,以实现目标。同时,我们还讨论了在没有指定ID时返回父节点和直接子节点,以及在指定ID没有子节点时返回空数组的策略。

在处理具有层级结构的分类数据时,经常需要根据特定的分类ID提取其所有子节点,并将这些节点扁平化到一个数组中。本教程将介绍一种使用JavaScript实现此功能的有效方法,该方法避免了使用for、forEach和while等传统循环结构,而是采用栈数据结构,提供了一种更简洁和可读性更高的解决方案。

数据结构

首先,我们假设有如下的数据结构,表示分类信息:

interface Category {  name: string;  id: string;  count: string;  depth: string;  children: Category[];}const data: Category[] = [  {    name: "Car",    id: "19",    count: "20",    depth: "1",    children: [      {        name: "Wheel",        id: "22",        count: "3",        depth: "2",        children: [          {            name: "Engine",            id: "101",            count: "1",            depth: "3",            children: [              {                name: "Engine and Brakes",                id: "344",                count: "1",                depth: "4",                children: []              }            ]          }        ]      }    ]  },  {    name: "Bike",    id: "3",    count: "12",    depth: "1",    children: [      {        name: "SpeedBike",        id: "4",        count: "12",        depth: "2",        children: []      }    ]  }];

实现方法

以下是实现提取指定ID子节点并扁平化的函数:

立即学习“Java免费学习笔记(深入)”;

interface Category {  name: string;  id: string;  count: string;  depth: string;  children: Category[];}const mapCategory = (category: Category) => ({  name: category.name,  id: category.id,  count: category.count,});const getCategoriesChildren = (  categoryIds: Category['id'][],  categories: Category[],) => {  const foundChildren: Pick[] = [];  if (categoryIds.length === 0) {    return categories.reduce<Pick[]>(      (acc, category) => {        acc.push(mapCategory(category), ...category.children.map(mapCategory));        return acc;      },      [],    );  }  const stack: (Category & { isDesired?: boolean })[] = [...categories];  while (stack.length) {    const category = stack.pop();    if (!category) continue;    const isDesiredCategory =      categoryIds.includes(category.id) || category.isDesired;    if (isDesiredCategory) {      foundChildren.push(...category.children.map(mapCategory));    }    stack.push(      ...(isDesiredCategory        ? category.children.map((child) => ({ ...child, isDesired: true }))        : category.children),    );  }  return foundChildren;};

代码解释:

mapCategory 函数: 用于提取每个分类的 name、id 和 count 属性,创建一个新的对象。getCategoriesChildren 函数:接收两个参数:categoryIds (要提取子节点的分类ID数组) 和 categories (分类数据数组)。如果 categoryIds 为空,则返回所有父节点和直接子节点。使用 reduce 方法遍历 categories 数组,将每个分类及其直接子节点映射到新的对象并添加到结果数组中。如果 categoryIds 不为空,则使用栈数据结构来遍历分类树。创建一个栈 stack,并将 categories 数组中的所有分类添加到栈中。使用 while 循环,只要栈不为空,就从栈中弹出一个分类。检查当前分类的 id 是否在 categoryIds 数组中,或者该分类是否是目标分类的后代节点(通过 isDesired 属性判断)。如果是目标分类或其后代节点,则将其子节点映射到新的对象并添加到 foundChildren 数组中。将当前分类的子节点添加到栈中,如果当前分类是目标分类,则将其子节点的 isDesired 属性设置为 true,表示这些子节点是目标分类的后代节点。最后,返回 foundChildren 数组。

使用示例

const categoryIds1 = ['22', '3'];const result1 = getCategoriesChildren(categoryIds1, data);console.log(result1);// Expected Output:// [//   { name: "Engine", id: "101", count: "1" },//   { name: "Engine and Brakes", id: "344", count: "1" },//   { name: "SpeedBike", id: "4", count: "12" }// ]const categoryIds2: string[] = [];const result2 = getCategoriesChildren(categoryIds2, data);console.log(result2);// Expected Output:// [//  { name: "Car", id: "19", count: "20" },//  { name: "Wheel", id: "22", count: "3" },//  { name: "Bike", id: "3", count: "12" },//  { name: "SpeedBike", id: "4", count: "12" }// ]const categoryIds3 = ['4'];const result3 = getCategoriesChildren(categoryIds3, data);console.log(result3);// Expected Output:// []

注意事项

该方法使用了栈数据结构来避免递归调用,从而提高了性能。isDesired 属性用于标记目标分类的后代节点,避免重复遍历。如果需要处理非常大的数据集,可以考虑使用Web Workers来将计算任务放在后台线程中执行,以避免阻塞主线程。

总结

本教程介绍了一种使用JavaScript从深度嵌套的分类数据中提取特定ID的子节点,并将结果扁平化为一个数组的有效方法。该方法避免了传统的循环结构,而是采用栈数据结构,提供了一种更简洁和可读性更高的解决方案。 通过理解和应用本教程中的代码,你可以更有效地处理具有层级结构的分类数据,并提取所需的信息。

以上就是从嵌套的分类数据中提取指定ID的子节点并扁平化:JavaScript教程的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1517407.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 10:44:39
下一篇 2025年12月20日 10:44:55

相关推荐

  • TypeScript 中强制泛型属性在嵌套数组中完全覆盖的类型检查实践

    本文探讨了在 typescript 中实现泛型类型属性在嵌套数组结构中强制完全覆盖的类型检查挑战。由于 typescript 缺乏原生“穷尽数组”概念,我们通过构建一套高级类型工具,包括精确的 `field` 定义和高阶函数 `fieldsgrouplayoutfor`,来在编译时验证所有属性是否被…

    2025年12月20日
    000
  • TypeScript 未赋值变量的真值检查与类型安全实践

    本教程深入探讨了 typescript 中处理未赋值变量进行真值检查时常见的类型错误。我们将解释为何将变量声明为 `object` 却未初始化会导致编译问题,并提供两种核心解决方案:使用 `object | undefined` 联合类型允许变量在赋值前为 `undefined`,或使用 `obje…

    2025年12月20日
    000
  • WebAssembly模块内存缓冲区清理与释放机制

    本文探讨了webassembly模块内存的清理与释放机制。核心内容指出,webassembly内存的生命周期与其javascript实例紧密关联。要彻底释放webassembly占用的内存,唯一有效的方法是确保所有指向`webassembly.instance`对象的javascript引用都被清除…

    2025年12月20日
    000
  • Blazor组件交互:实现子组件按钮的异步禁用与启用

    本文详细介绍了在blazor应用中,如何通过异步编程和ui线程协调,实现子组件按钮在触发父组件耗时操作期间的自动禁用与操作完成后的重新启用。核心在于利用`async`/`await`模式和`task.delay(1)`来确保ui在异步操作开始前及时更新,从而提供流畅的用户体验。 在Blazor应用开…

    2025年12月20日
    000
  • 掌握Next.js中getStaticProps的数据传递机制与常见陷阱

    本教程深入探讨Next.js中`getStaticProps`函数如何向页面组件传递数据。我们将纠正关于手动传递props的常见误解,详细阐述Next.js的自动prop注入机制,并提供针对`undefined`数据问题的实用故障排除指南。通过理解`getStaticProps`的服务器端执行特性,…

    2025年12月20日
    000
  • JavaScript对象数据动态渲染HTML表格教程

    本教程将指导您如何使用javascript将对象数据动态地渲染到html表格中。我们将通过一个简单的图书馆书籍管理项目为例,学习如何构造数据对象、存储数据,以及在用户交互时动态更新html表格,确保数据展示的准确性和页面的响应性。教程将强调结构清晰的代码组织和dom操作的最佳实践。 在现代Web开发…

    2025年12月20日
    000
  • 优化React-Redux应用中的用户与受保护数据按需加载

    本教程旨在解决React-Redux应用中用户数据和受保护API密钥在用户未登录时仍被请求,导致401错误的问题。通过引入条件性Redux状态初始化和动作分发逻辑,确保只有在用户被认为已认证时才发起相关的API请求,从而优化应用性能,减少不必要的网络流量和控制台错误。 在构建现代Web应用时,尤其是…

    2025年12月20日
    000
  • TypeScript 中未赋值对象真值检查的正确处理姿势

    本文深入探讨了在 typescript 中对可能未赋值的变量进行真值检查时遇到的常见问题及其解决方案。当 typescript 严格检查变量类型时,直接对声明为 `object` 但尚未赋值的变量进行 `if (variable)` 判断会导致编译错误。通过引入联合类型 `object | unde…

    2025年12月20日
    000
  • JavaScript深拷贝与浅拷贝机制

    浅拷贝复制对象第一层属性,引用类型共享内存地址,修改嵌套对象会影响原对象,常用方法有Object.assign、扩展运算符等;深拷贝递归复制所有层级,生成完全独立的新对象,修改副本不影响原对象,但性能开销大,可用JSON.parse(JSON.stringify())或_.cloneDeep()实现…

    2025年12月20日
    000
  • Angular 15 表单中单选按钮验证消息不显示的解决方案

    本文深入探讨了在 angular 15 应用中,单选按钮(radio buttons)的必填验证消息无法正确显示的问题。核心原因在于 `touched` 状态与 `required` 验证器的结合方式。文章提供了两种解决方案:一是调整验证条件的判断逻辑,移除 `touched` 状态的限制;二是为单…

    2025年12月20日
    000
  • Yup验证中的对象类型错误与自定义API错误处理指南

    本教程深入探讨了在使用yup进行表单验证时常见的`object`类型错误,并提供了正确的对象验证方法。同时,文章详细介绍了如何利用yup的`test`方法和上下文(context)机制,优雅地集成和展示来自服务器api的自定义错误信息,从而提升表单验证的灵活性和用户体验。 理解Yup的对象验证机制 …

    2025年12月20日
    000
  • JavaScript共享内存与原子操作

    JavaScript通过SharedArrayBuffer实现多线程间共享内存,结合Atomics对象提供的原子操作确保数据安全。1. SharedArrayBuffer允许主线程与Web Workers共享同一块内存,实现高效数据传递;2. Atomics提供load、store、add、sub、…

    2025年12月20日
    000
  • JavaScript函数柯里化与组合

    函数柯里化是将多参数函数转换为单参数函数序列,组合则是将多个函数串联执行。通过curry实现参数累积,compose或pipe实现函数流水线,二者结合可构建灵活的数据处理链,如transform = pipe(trim, toUpper, wrap(‘div’)),提升代码复…

    2025年12月20日
    000
  • Angular 模板驱动表单中单选按钮验证消息不显示的解决方案与默认值设置

    本文深入探讨了angular模板驱动表单中单选按钮验证消息不显示的问题,核心原因在于对`touched`状态的误解。我们将详细解释为何在单选按钮组上单独使用`touched`可能导致验证消息失效,并提供移除`touched`条件的解决方案。此外,文章还将指导如何在组件中设置单选按钮的默认选中值,以提…

    2025年12月20日
    000
  • 解决 Angular NgModel 表单中单选按钮验证消息不显示的问题

    本文深入探讨了 Angular NgModel 驱动表单中,单选按钮 `required` 验证消息无法正确显示的问题。核心原因是 `touched` 状态的误用,导致在用户未与单选按钮组交互时,验证错误信息被隐藏。文章提供了详细的解决方案,即移除 `*ngIf` 条件中的 `touched` 检查…

    2025年12月20日
    000
  • Yup验证中object类型错误解析与API响应集成

    在前端开发中,数据验证是确保数据完整性和用户体验的关键环节。yup作为一个流行的javascript schema验证库,提供了强大且灵活的验证能力。然而,在使用过程中,开发者可能会遇到一些常见的陷阱,例如this must be a object type, but the final value…

    2025年12月20日
    000
  • 解决Hardhat配置中环境变量未定义错误:dotenv加载顺序指南

    本文旨在解决hardhat项目中常见的`referenceerror: api_url_key is not defined`错误。该问题通常源于`dotenv`模块加载顺序不当,导致环境变量在被引用时尚未初始化。教程将通过示例代码详细指导如何将`require(‘dotenv&#821…

    2025年12月20日
    000
  • Yup验证中“必须是对象”错误解析与服务器端错误集成

    在yup验证中遇到“必须是对象”的错误通常是由于验证器期望接收一个完整的数据对象,但实际传入了单个字段的值。本文将详细解释此类型不匹配的原因及解决方案,并通过示例代码演示如何正确传递数据进行验证。此外,还将深入探讨如何利用yup的`test`方法和`context`机制,优雅地集成和展示来自服务器端…

    2025年12月20日
    000
  • Angular 15 模板驱动表单:解决单选按钮验证消息不显示问题及默认值设置

    本教程深入探讨了 angular 15 模板驱动表单中单选按钮组验证消息不显示的问题。核心在于 `touched` 属性与 `required` 验证的交互,并提供了移除 `touched` 条件的解决方案。同时,文章还详细介绍了如何在组件中为单选按钮设置默认选中值,确保表单的初始状态符合业务需求,…

    2025年12月20日
    000
  • JavaScript中将函数作为参数传递:行为与应用

    在javascript中,函数是第一类对象,可以像其他数据类型一样被传递。当一个函数作为参数传递给另一个函数时,其执行与否、何时执行、如何执行,完全取决于接收该参数的函数的内部逻辑。本文将深入探讨这种机制,并通过示例阐明函数作为参数时的不同行为模式及其常见应用场景。 引言:JavaScript中的第…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信