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

如何按isOptional字段拆分递归数组并保留父路径结构

递归拆分嵌套子项结构:分离isOptional不同值的完整路径

需求说明

处理一个含递归层级的packagedItems结构(子项同样包含item和嵌套子项,层级无限制),将所有包含isOptional: true的节点路径、以及isOptional: false的节点路径分别拆分,返回两个与输入结构完全一致的数组。

输入示例

const product = {
  name: "Product 1",
  packagedItems: [
    {
      id: 1,
      isOptional: false,
      item: {
        name: "1#1",
        packagedItems: [
          {
            id: 3,
            isOptional: false,
            item: {
              name: "2#1",
              packagedItems: [
                {
                  id: 5,
                  isOptional: false,
                  item: {
                    name: "3#1",
                    packagedItems: []
                  }
                },
                {
                  id: 6,
                  isOptional: true,
                  item: {
                    name: "3#2",
                    packagedItems: []
                  }
                }
              ]
            }
          }
        ]
      }
    },
    {
      id: 2,
      isOptional: false,
      item: {
        name: "1#2",
        packagedItems: [
          {
            id: 4,
            isOptional: false,
            item: {
              name: "2#2",
              packagedItems: [
                {
                  id: 7,
                  isOptional: true,
                  item: {
                    name: "3#3",
                    packagedItems: []
                  }
                },
                {
                  id: 8,
                  isOptional: true,
                  item: {
                    name: "3#4",
                    packagedItems: []
                  }
                }
              ]
            }
          }
        ]
      }
    }
  ]
};

尝试的代码(仅获取父级名称,无法构建完整结构)

const getParents = (
  packagedItems: PackagedItem[],
  ancestors: (string | PackagedItem)[] = []
): any => {
  for (let pack of packagedItems) {
    if (pack.isOptional && !pack.item.packagedItems.length) {
      return ancestors.concat(pack);
    }
    const found = getParents(
      pack.item.packagedItems,
      ancestors.concat(pack.item.name)
    );
    if (found) {
      return found;
    }
  }
  return undefined;
};

console.log(getParents(product.packagedItems));

当前返回结果

[
  "1#1",
  "2#1",
  {
    id: 6,
    isOptional: true,
    item: Object
  }
]

预期结果

const optionalTrue = [
  {
    id: 1,
    isOptional: false,
    item: {
      name: "1#1",
      packagedItems: [
        {
          id: 3,
          isOptional: false,
          item: {
            name: "2#1",
            packagedItems: [
              {
                id: 6,
                isOptional: true,
                item: {
                  name: "3#2",
                  packagedItems: []
                }
              }
            ]
          }
        }
      ]
    }
  },
  {
    id: 2,
    isOptional: false,
    item: {
      name: "1#2",
      packagedItems: [
        {
          id: 4,
          isOptional: false,
          item: {
            name: "2#2",
            packagedItems: [
              {
                id: 7,
                isOptional: true,
                item: {
                  name: "3#3",
                  packagedItems: []
                }
              },
              {
                id: 8,
                isOptional: true,
                item: {
                  name: "3#4",
                  packagedItems: []
                }
              }
            ]
          }
        }
      ]
    }
  }
];

const optionalFalse = [
  {
    id: 1,
    isOptional: false,
    item: {
      name: "1#1",
      packagedItems: [
        {
          id: 3,
          isOptional: false,
          item: {
            name: "2#1",
            packagedItems: [
              {
                id: 5,
                isOptional: false,
                item: {
                  name: "3#1",
                  packagedItems: []
                }
              }
            ]
          }
        }
      ]
    }
  }
];

解决方案代码

function splitByIsOptional(packagedItems) {
  const result = {
    optionalTrue: [],
    optionalFalse: []
  };

  for (const pack of packagedItems) {
    // 递归处理当前节点的子项
    const childSplit = splitByIsOptional(pack.item.packagedItems);

    // 构建optionalTrue分支的节点副本
    const trueNode = { ...pack, item: { ...pack.item } };
    trueNode.item.packagedItems = childSplit.optionalTrue;
    // 若当前节点是可选,或子项存在可选节点,则加入optionalTrue数组
    if (pack.isOptional || trueNode.item.packagedItems.length > 0) {
      result.optionalTrue.push(trueNode);
    }

    // 构建optionalFalse分支的节点副本(仅处理非可选节点)
    if (!pack.isOptional) {
      const falseNode = { ...pack, item: { ...pack.item } };
      falseNode.item.packagedItems = childSplit.optionalFalse;
      // 若子项存在非可选节点,或当前节点无任何子项,则加入optionalFalse数组
      if (falseNode.item.packagedItems.length > 0 || pack.item.packagedItems.length === 0) {
        result.optionalFalse.push(falseNode);
      }
    }
  }

  return result;
}

// 调用函数并获取结果
const { optionalTrue, optionalFalse } = splitByIsOptional(product.packagedItems);
console.log('optionalTrue:', optionalTrue);
console.log('optionalFalse:', optionalFalse);

代码说明

  • 递归遍历:对每个层级的packagedItems进行递归处理,确保覆盖所有嵌套层级
  • 节点副本:每次处理节点时创建浅拷贝(避免修改原数据),并替换子项为对应分类的结果
  • 分类逻辑:
    • optionalTrue:保留所有包含可选节点的完整路径,只要当前节点是可选,或子项中有可选节点,就保留该节点结构
    • optionalFalse:仅保留非可选节点的路径,只有当前节点为非可选,且子项存在非可选节点或无任何子项时,才保留该节点结构
  • 结构一致性:最终返回的两个数组结构与输入完全匹配,仅过滤掉不符合分类条件的子项

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 20:25:59