【问题标题】:How to aggregate nested values in array of objects如何聚合对象数组中的嵌套值
【发布时间】:2021-09-22 18:55:54
【问题描述】:

我有一个现有函数,它从两个数组(一个数组是交易数据,另一个是主数据)创建一个汇总对象。

目前,返回的对象包含按年和月的交易数量之和 - 示例如下。

我正在寻求帮助,以便在每个项目的根级别添加总和 - 示例如下。

我已经查看了类似问题的答案,但找不到与我的用例足够接近的解决方案。

这是现有的代码:

const
    array1 = [{ material: "ABC123", cost: 100 },
              { material: "DEF456", cost: 150 }],
    array2 = [{ material: "ABC123", date: "1/1/20", quantity: 4 },
              { material: "ABC123", date: "1/15/20", quantity: 1 },
              { material: "ABC123", date: "2/15/20", quantity: 3 },
              { material: "ABC123", date: "4/15/21", quantity: 1 },
              { material: "DEF456", date: "3/05/20", quantity: 6 },
              { material: "DEF456", date: "3/18/20", quantity: 1 },
              { material: "DEF456", date: "5/15/21", quantity: 2 }],
    groups = [
        ({ material }) => material,
        _ => 'byYear',
        ({ date }) => '20' + date.split('/')[2],
        _ => 'byMonth'
    ],
    sum = {
        key: ({ date }) => date.split('/')[0],
        value: ({ quantity }) => quantity
    }, 
    result = array2.reduce(
        (r, o) => {
            const temp = groups.reduce((t, fn) => t[fn(o)] ??= {}, r);
            temp[sum.key(o)] ??= 0;
            temp[sum.key(o)] += sum.value(o);
            return r;
        },
        Object.fromEntries(array1.map(({ material, cost }) => [material, { cost }]))
    );

console.log(result);

如上所述,我希望它在根级别添加一个“totalSum”键/值。结果如下:

{
"ABC123": {
    "totalSum": 8,
    "cost": 100,
    "byYear": {
        "2020": {
            "byMonth": {
                "1": {
                    "sum": 5,
                    "max": 4
                },
                "2": {
                    "sum": 3,
                    "max": 3
                    }
                }
            }
        }
    }
}

非常感谢任何帮助!

【问题讨论】:

    标签: javascript arrays object lodash


    【解决方案1】:

    您实际上可以通过单个 Array#reduce() 调用实现整个重构,并结合 master 数组的 Map 来检索 cost

    添加一个总和是微不足道的,因为您拥有所有的属性并且不必重新映射您的聚合数据。

    const
      array1 = [{ material: "ABC123", cost: 100, critical: true }, { material: "DEF456", cost: 150, critical: false }],
      array2 = [{ material: "ABC123", date: "1/1/20", quantity: 4 }, { material: "ABC123", date: "1/15/20", quantity: 1 }, { material: "ABC123", date: "2/15/20", quantity: 3 }, { material: "ABC123", date: "4/15/21", quantity: 1 }, { material: "DEF456", date: "3/05/20", quantity: 6 }, { material: "DEF456", date: "3/18/20", quantity: 1 }, { material: "DEF456", date: "5/15/21", quantity: 2 }],
    
      master = new Map(array1.map(({ material, ...item }) => [material, item])),
      result = array2.reduce((acc, { material, date, quantity }) => {
        let [month, , year] = date.split('/');
        year = '20' + year;
    
        const
          _material = (acc[material] ??= { ...master.get(material), totalSum: 0, byYear: {} }),
          _byYear = (_material.byYear[year] ??= { byMonth: {} }),
          _byMonth = (_byYear.byMonth[month] ??= { sum: 0, max: 0 });
    
        _material.totalSum += quantity;
        _byMonth.sum += quantity;
        _byMonth.max = Math.max(_byMonth.max, quantity);
    
        return acc;
      }, {});
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    编辑

    在您提到的评论中,您可能在array1 中有更多属性应该包含在最终结果中。我通过更改Map 以引用array1 中的整个对象来进行编辑以适应这一点。然后,当我们第一次在累加器中声明相关对象时,我们可以使用spread syntax 包含所有可用的属性。

    // split out 'material' from the rest of the object in the Map
    const master = new Map(array1.map(({ material, ...item }) => [material, item]));
    
    // later access the object by material and spread its props into the accumulator object.
    _material = (acc[material] ??= { ...master.get(material), totalSum: 0, byYear: {} }),
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-09
      • 2018-09-10
      • 2023-01-12
      • 2021-07-20
      • 2021-08-13
      • 2020-01-24
      • 2022-01-22
      • 2020-04-23
      相关资源
      最近更新 更多