Given 是一个数据项数组,其中需要对每个属性的值进行求和,其中其键与附加提供的属性名称(用作分组键)不同。
因此,对于分组键
name
和样本数据,如 ...
[{
name: "Name1",
amt: 100,
tax: 10,
total: 110,
}, {
name: "Name2",
amt: 50,
tax: 5,
total: 55,
}, {
name: "Name1",
amt: 70,
tax: 7,
total: 77,
}]
...预期结果是...
[{
name: "Name1",
amt: 170,
tax: 17,
total: 187,
}, {
name: "Name2",
amt: 50,
tax: 5,
total: 55,
}]
有没有一种方法或参考可以产生像上面这样的输出?
使用
Array::reduce()
构造一个新数组,通过映射中的名称记住项目并将其放入结果数组中,并使用映射以新总计更新项目:
const result = arr.reduce((r, {name, ...item}) => {
const found = r.map.get(name);
if(found){
Object.keys(item).forEach(key => found[key] += item[key]);
} else {
r.map.set(name, r.arr[r.arr.length] = {name, ...item});
}
return r;
}, {arr: [], map: new Map}).arr;
console.log(result);
<script>
const arr = [
{
name: "Name1",
amt : 100,
tax : 10,
total : 110
},
{
name: "Name2",
amt : 50,
tax : 5,
total : 55
},
{
name: "Name1",
amt : 70,
tax : 7,
total : 77
}
]
</script>
您可以通过键值将每个对象缩减为映射。对于每个项目,循环遍历键并忽略
key
参数。
将传入的
item[k]
求和到 existing[k]
条目上。
最后,返回
values()
的 Map
并将迭代器展开到新的 Array
对象中。
const reduceBy = (data, key) =>
[...data.reduce((map, item) => {
const existing = map.get(item[key]) ?? { [key]: item[key] };
for (let k in item) {
if (k !== key) {
existing[k] = (existing[k] ?? 0) + item[k];
}
}
return map.set(item[key], existing);
}, new Map).values()];
const
input = [
{ name: "Name1", amt: 100, tax: 10, total: 110 },
{ name: "Name2", amt: 50, tax: 5, total: 55 },
{ name: "Name1", amt: 70, tax: 7, total: 77 }
],
expected = [
{ name: "Name1", amt: 170, tax: 17, total: 187 },
{ name: "Name2", amt: 50, tax: 5, total: 55 }
],
actual = reduceBy(input, 'name');
console.log(JSON.stringify(actual) === JSON.stringify(expected));
.as-console-wrapper { top: 0; max-height: 100% !important; }