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

基于Id和ParentId重组嵌套数组并过滤无in_shop属性的节点

问题:将扁平数组转为嵌套结构并过滤无有效分支的项

需求说明

需要把扁平数组按parentFolderId构建嵌套层级结构,同时移除**自身及所有子级、子级的子级都不包含in_shop: true**的项。

输入示例

const menuItems = [
  {
    id: 1,
    displayName: "Equipment",
    parentFolderId: null,
    // ... 其他属性
  },
  {
    id: 2,
    displayName: "Equipment",
    parentFolderId: 6,
    // ... 其他属性
  },
  {
    id: 3,
    displayName: "Equipment",
    parentFolderId: 2,
    in_shop: true
    // ... 其他属性
  }, 
  {
    id: 4,
    displayName: "Equipment",
    parentFolderId: 1,
    // ... 其他属性
  },
  {
    id: 5,
    displayName: "Equipment",
    parentFolderId: 1,
    // ... 其他属性
  },
  {
    id: 6,
    displayName: "Equipment",
    parentFolderId: null,
    // ... 其他属性
  },
  {
    id: 7,
    displayName: "Equipment",
    parentFolderId: 5,
    in_shop: true,
    // ... 其他属性
  },
  {
    id: 8,
    displayName: "Equipment",
    parentFolderId: 3,
    // ... 其他属性
  },
  // ... 更多对象
];

期望输出

const menuItems = [
  {
    id: 1,
    displayName: "Equipment",
    parentFolderId: null,
    // ... 其他属性
    children: [
      {
        id: 5,
        displayName: "Equipment",
        parentFolderId: 1,
        children: [
          {
            id: 7,
            displayName: "Equipment",
            parentFolderId: 5,
            in_shop: true,
            // ... 其他属性
          },
        ]
        // ... 其他属性
      },
    ],
  },

  {
    id: 6,
    displayName: "Equipment",
    parentFolderId: null,
    // ... 其他属性
    children: [
      {
        id: 2,
        displayName: "Equipment",
        parentFolderId: 6,
        // ... 其他属性
        children: [
          {
            id: 3,
            displayName: "Equipment",
            parentFolderId: 2,
            in_shop: true,
            // ... 其他属性
          },
        ],
      },
    ],
  },
  // ... 更多对象
]

当前实现代码

已完成嵌套结构构建,但未实现过滤逻辑:

function addChild(obj) {
    // 获取子项并递归处理
    let children = menuItems.filter(a => a.parentFolderId == obj.id).map(addChild)

    // 如果有子项则添加children属性
    if (children.length > 0 ) {
      return { ...obj, children }
    }

    // 无子项则返回原对象
    return { ...obj }
  }
const result = menuItems.filter(a => a.parentFolderId == null).map(addChild)

解决方案

核心逻辑是自底向上判断分支是否保留:节点是否保留,取决于自身有in_shop: true,或者存在可保留的子分支。

修改后的代码如下:

function processItem(obj) {
    // 递归处理所有子项,过滤掉无效分支
    const validChildren = menuItems
        .filter(item => item.parentFolderId === obj.id)
        .map(processItem)
        // 移除返回null的无效子节点
        .filter(child => child !== null);

    // 判断当前节点是否需要保留:自身有in_shop,或者有有效子节点
    const shouldKeep = obj.in_shop === true || validChildren.length > 0;

    if (!shouldKeep) {
        return null; // 不保留则返回null,上层会过滤掉
    }

    // 有有效子节点则添加children属性,否则返回原对象
    return validChildren.length > 0 
        ? { ...obj, children: validChildren } 
        : { ...obj };
}

const result = menuItems
    .filter(item => item.parentFolderId === null)
    .map(processItem)
    .filter(item => item !== null); // 过滤掉根节点中的无效项

代码说明

  1. 递归处理子项:先递归处理所有子节点,得到过滤后的有效子节点列表;
  2. 判断保留条件:当前节点自身有in_shop: true,或者存在有效子节点,才会被保留;
  3. 过滤无效节点:返回null的节点会被上层的filter移除,最终只保留符合要求的分支。

比如示例中的id=4节点,自身无in_shop且没有有效子节点,会被过滤;id=1节点因为有id=5这个有效子分支,所以会被保留。

内容的提问来源于stack exchange,提问作者Latent-code

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:35:27