如何聚合对象数组中的嵌套值
How to aggregate nested values in array of objects
我有一个现有函数,可以从两个数组(一个数组是交易数据,另一个是主数据)创建一个汇总对象。
目前,返回的对象包含按年和按月的交易数量总和-示例如下。
我正在寻求帮助以在根级别为每个项目添加总和 - 下面还有示例。
我查看了类似问题的答案,但未能找到足够接近我的用例的解决方案。
这是现有代码:
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”key/value。结果如下:
{
"ABC123": {
"totalSum": 8,
"cost": 100,
"byYear": {
"2020": {
"byMonth": {
"1": {
"sum": 5,
"max": 4
},
"2": {
"sum": 3,
"max": 3
}
}
}
}
}
}
非常感谢任何帮助!
您实际上可以通过 master
数组的单个 Array#reduce()
call, combined with a 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: {} }),
我有一个现有函数,可以从两个数组(一个数组是交易数据,另一个是主数据)创建一个汇总对象。
目前,返回的对象包含按年和按月的交易数量总和-示例如下。
我正在寻求帮助以在根级别为每个项目添加总和 - 下面还有示例。
我查看了类似问题的答案,但未能找到足够接近我的用例的解决方案。
这是现有代码:
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”key/value。结果如下:
{
"ABC123": {
"totalSum": 8,
"cost": 100,
"byYear": {
"2020": {
"byMonth": {
"1": {
"sum": 5,
"max": 4
},
"2": {
"sum": 3,
"max": 3
}
}
}
}
}
}
非常感谢任何帮助!
您实际上可以通过 master
数组的单个 Array#reduce()
call, combined with a 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: {} }),