代码之家  ›  专栏  ›  技术社区  ›  lrr59

如何在递归数组中合并数据

  •  1
  • lrr59  · 技术社区  · 2 年前

    我有一系列项目,顺序如下:

    const arr = [
      {
        group: { id: "group1", groupname: "groupname1" },
        categories: [
          {
            id: "cat1",
            categoryName: "category1",
            total: 5,
            available: 2,
            subCategories: []
          },
          {
            id: "cat2",
            categoryName: "category2",
            total: 15,
            available: 12,
            subCategories: [
              {
                id: "cat3",
                categoryName: "category3",
                total: 15,
                available: 12,
                subCategories: []
              }
            ]
          }
        ]
      },
      {
        group: { id: "group2", groupname: "groupname2" },
        categories: [
          {
            id: "cat4",
            categoryName: "category4",
            total: 25,
            available: 22,
            subCategories: []
          },
          {
            id: "cat5",
            categoryName: "category5",
            total: 50,
            available: 25,
            subCategories: []
          }
        ]
      }
    ];
    

    这需要转换为递归项数组、witj键、名称和子属性。结果是这样的,

    [
      {
        "key": "group1",
        "name": "groupname1",
        "total": 20,
        "available": 24,
        "children": [
          {
            "key": "cat1",
            "name": "category1",
            "total": 5,
            "available": 2,
            "children": []
          },
          {
            "key": "cat2",
            "name": "category2",
            "total": 15,
            "available": 12,
            "children": [
              {
                "key": "cat3",
                "name": "category3",
                "total": 15,
                "available": 12,
                "children": []
              }
            ]
          }
        ]
      },
      {
        "key": "group2",
        "name": "groupname2",
        "total": 75,
        "available": 47,
        "children": [
          {
            "key": "cat4",
            "name": "category4",
            "total": 25,
            "available": 22,
            "children": []
          },
          {
            "key": "cat5",
            "name": "category5",
            "total": 50,
            "available": 25,
            "children": []
          }
        ]
      }
    ]
    

    我可以使用下面的片段来简化到上面的结构。

    const formatter = (data) => {
      const recursiveTree = (item) => {
        if (item.group) {
          const {
            group: { id, groupname, total, available },
            categories
          } = item;
          return {
            key: id,
            name: groupname,
            total: total || 0,
            available: available || 0,
            children: categories?.map(recursiveTree)
          };
        }
        const { id, categoryName, total, available, subCategories } = item;
        return {
          key: id,
          name: categoryName,
          total: total || 0,
          available: available || 0,
          children: subCategories.map(recursiveTree)
        };
      };
      return data.map(recursiveTree);
    };
    

    我一直在推导根音符的总数和可用性。此节点应从其子节点值中导出其合计值和可用值。有人能帮我如何递归地做这件事吗?这也可能是n级

    1 回复  |  直到 2 年前
        1
  •  0
  •   trincot    2 年前

    你可以添加一些后期处理。替换此:

      return data.map(recursiveTree);
    

    与:

      const result = data.map(recursiveTree);
      for (const item of result) {
          if (!item.children) continue;
          item.total = item.children.reduce((total, child) => total + child.total, 0);
          item.available = item.children.reduce((total, child) => total + child.available, 0);
      }
      return result;
    
        2
  •  -1
  •   Scott Sauyet    2 年前

    一种方法将输入结构的重新格式化和属性的合计分离开来。这里我们有一个非变异版本,其工作原理如下:

    const restructure = (xs) => xs .map (x => ({
      key: x ?.group ?.id ?? x .id,
      name: x ?.group ?.groupname ?? x .categoryName,
      total: x .total ?? 0,
      available: x .available ?? 0,
      children: restructure (x .categories ?? x .subCategories)
    }))
    
    const sumOn = (field) => ({[field]: fld, children = [], ...rest}, _, __, kids = children .map (sumOn (field))) => ({
      ...rest,
      [field]: fld + kids .reduce ((t, kid) => t + kid [field], 0),
      children: kids
    })
    
    const process = (xs) => 
      restructure (arr) .map (sumOn ('total')) .map (sumOn ('available'))
    
    const arr = [{group: {id: "group1", groupname: "groupname1"}, categories: [{id: "cat1", categoryName: "category1", total: 5, available: 2, subCategories: []}, {id: "cat2", categoryName: "category2", total: 10, available: 5, subCategories: [{id: "cat3", categoryName: "category3", total: 15, available: 12, subCategories: []}]}]}, {group: {id: "group2", groupname: "groupname2"}, categories: [{id: "cat4", categoryName: "category4", total: 25, available: 22, subCategories: []}, {id: "cat5", categoryName: "category5", total: 50, available: 25, subCategories: []}]}]
    
    
    console .log (process (arr))
    .as-console-wrapper {max-height: 100% !important; top: 0}

    在这里 restructure 将稍微奇怪的输入转换为一致的递归结构。 sumOn 取一个字段名并返回一个函数,该函数通过递归地添加其每个字段的值来合计该字段的值 children 。(如果有 sum 帮手但我们可以把它当作练习。)

    我们的主要功能, process ,只是简单地调用 重组 输入,然后映射 sumOn 两次检查结果,一次检查结果 'total' 和一次 'available'

    我发现这是一种非常干净的方法,可以将问题分解为可重复使用的块和简单的步骤。