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

如何在JS/TS中获取指定分类ID子节点并扁平化(禁用循环)

问题描述

给定如下嵌套数据:

const data = [
    {
      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(如['22', '3']):获取这些ID对应的所有子节点并扁平化,返回剔除depth和children的精简对象数组
  • 未传入分类ID:默认返回所有父节点(depth=1)及其直接子节点的精简对象数组
  • 传入的分类ID无子女节点:返回空数组[]

要求:避免使用for、forEach、while循环,需适配任意多层嵌套的节点结构,支持JavaScript/TypeScript。


解决方案

1. 核心工具函数

扁平化节点的所有后代

用递归+flatMap实现,自动处理嵌套层级并返回精简后的节点数组:

const flattenDescendants = (node) => {
  return node.children.length === 0 
    ? [] 
    : node.children.flatMap(child => [
        { name: child.name, id: child.id, count: child.count },
        ...flattenDescendants(child)
      ]);
};

根据ID递归查找节点

用reduce遍历节点树,找到匹配ID的节点:

const findNodeById = (nodes, id) => {
  return nodes.reduce((found, node) => {
    if (found) return found;
    if (node.id === id) return node;
    return findNodeById(node.children, id);
  }, undefined);
};

2. 主函数实现

整合工具函数,覆盖所有需求场景:

const getTargetNodes = (categoryIds) => {
  // 处理未传入ID的默认场景
  if (!categoryIds || categoryIds.length === 0) {
    return data.flatMap(node => [
      { name: node.name, id: node.id, count: node.count },
      ...node.children.map(child => ({ name: child.name, id: child.id, count: child.count }))
    ]);
  }

  // 处理传入ID的场景
  return categoryIds.flatMap(id => {
    const targetNode = findNodeById(data, id);
    return targetNode ? flattenDescendants(targetNode) : [];
  });
};

3. TypeScript类型优化(可选)

为了代码严谨性,可添加类型定义:

interface Node {
  name: string;
  id: string;
  count: string;
  depth: string;
  children: Node[];
}

interface SimplifiedNode {
  name: string;
  id: string;
  count: string;
}

const flattenDescendants = (node: Node): SimplifiedNode[] => {
  return node.children.length === 0 
    ? [] 
    : node.children.flatMap(child => [
        { name: child.name, id: child.id, count: child.count },
        ...flattenDescendants(child)
      ]);
};

const findNodeById = (nodes: Node[], id: string): Node | undefined => {
  return nodes.reduce((found, node) => {
    if (found) return found;
    if (node.id === id) return node;
    return findNodeById(node.children, id);
  }, undefined);
};

const getTargetNodes = (categoryIds?: string[]): SimplifiedNode[] => {
  if (!categoryIds || categoryIds.length === 0) {
    return data.flatMap(node => [
      { name: node.name, id: node.id, count: node.count },
      ...node.children.map(child => ({ name: child.name, id: child.id, count: child.count }))
    ]);
  }

  return categoryIds.flatMap(id => {
    const targetNode = findNodeById(data as Node[], id);
    return targetNode ? flattenDescendants(targetNode) : [];
  });
};

4. 测试验证

  • 传入['22', '3']:返回预期的3个子节点数组
  • 不传入参数:返回父节点+直接子节点的数组
  • 传入无子女节点的ID(如['344']):返回空数组[]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:53:23