我正在尝试使用reduce方法对对象数组进行排序。我的目标是创建一个可以处理任意数量的对象(具有唯一的 eventId)的 reduce 方法。所需的输出将采用如下格式,但能够处理超过五个唯一的 eventId
[所需输出]
(5) [{…}, {…}, {…}, {…}, {…}]
0:
eventId: "12345"
total: Array(3)
0: {total: 123}
1: {total: 45}
2: {total: 123}
length: 3
1: {total: Array(3), eventId: '12347'}
2: {total: Array(3), eventId: '12349'}
3: {total: Array(3), eventId: '12348'}
4: {total: Array(3), eventId: '12346'}
为了获得上面的输出,我使用了这个reduce方法。
[减少方法]
const sortedSalesData = salesData.reduce((acc, obj) => {
for ( let i = 0; i<salesData.length; i++) {
if (obj.eventId === salesData[i].eventId ) {
acc[i].eventId = salesData[i].eventId;
acc[i].total = [...acc[i].total, {total: obj.total}];
return acc;
}
};
},[{total:[]},{total:[]},{total:[]},{total:[]},{total:[]}]);
但我不确定如何设置它来处理超过这五个唯一的 eventId。以下是原始数组供参考。
[原始数组]
const salesData =
[
{ eventId: '12345', total: 123 },
{ eventId: '12347', total: 45 },
{ eventId: '12349', total: 78 },
{ eventId: '12348', total: 123 },
{ eventId: '12346', total: 45 },
{ eventId: '12349', total: 78 },
{ eventId: '12347', total: 123 },
{ eventId: '12345', total: 45 },
{ eventId: '12348', total: 78 },
{ eventId: '12345', total: 123 },
{ eventId: '12347', total: 45 },
{ eventId: '12346', total: 78 },
{ eventId: '12349', total: 123 },
{ eventId: '12348', total: 45 },
{ eventId: '12346', total: 78 },
];
挂断使其能够处理任意数量的唯一事件,而无需在方法末尾添加额外的 {total:[]}。
您想要迭代初始数组(obj),如果 eventId 在该数组上尚不存在(accObj),则将迭代的元素插入到新数组(acc)中,当它确实存在(accObj)时,您想要推送总数当前元素(obj)的对象到新元素(accObj)的总数组中?
我认为这可以满足您的需要:
let array = [
{ eventId: '12345', total: 123 },
{ eventId: '12347', total: 45 },
{ eventId: '12349', total: 78 },
{ eventId: '12348', total: 123 },
{ eventId: '12346', total: 45 },
{ eventId: '12349', total: 78 },
{ eventId: '12347', total: 123 },
{ eventId: '12345', total: 45 },
{ eventId: '12348', total: 78 },
{ eventId: '12345', total: 123 },
{ eventId: '12347', total: 45 },
{ eventId: '12346', total: 78 },
{ eventId: '12349', total: 123 },
{ eventId: '12348', total: 45 },
{ eventId: '12346', total: 78 },
]
let reducedArray = array.reduce((acc, obj) => {
console.log("Element " + JSON.stringify(obj));
let accObj = acc.find(accObj => accObj.eventId === obj.eventId);
if(accObj != undefined) {
console.log("Found element: " + JSON.stringify(accObj) + ".")
console.log("Pushing "+ obj.total +" to total.")
accObj.total.push(obj.total);
} else {
accObj = { eventId: obj.eventId, total: [obj.total] };
console.log("Pushing new element to list: " + JSON.stringify(accObj));
acc.push(accObj);
}
return acc;
}, []);
console.log(JSON.stringify(reducedArray));
技巧在于
find
方法,我正在搜索自己的缩减列表,看看它是否已经有一个与旧数组共享 eventId 的元素。
我不喜欢 .reduce 所以这是一个没有它的简单解决方案
const salesData =
[
{ eventId: '12345', total: 123 },
{ eventId: '12347', total: 45 },
{ eventId: '12349', total: 78 },
{ eventId: '12348', total: 123 },
{ eventId: '12346', total: 45 },
{ eventId: '12349', total: 78 },
{ eventId: '12347', total: 123 },
{ eventId: '12345', total: 45 },
{ eventId: '12348', total: 78 },
{ eventId: '12345', total: 123 },
{ eventId: '12347', total: 45 },
{ eventId: '12346', total: 78 },
{ eventId: '12349', total: 123 },
{ eventId: '12348', total: 45 },
{ eventId: '12346', total: 78 },
]
let reduced = {}
salesData.forEach(elem=> {
if(reduced[elem.eventId] !== undefined){
reduced[elem.eventId].push(elem.total)
} else {
reduced[elem.eventId] = [elem.total]
}
})
reduced = Object.keys(reduced).map(elem => {
return({eventId: elem, total:reduced[elem]})
})
console.log(reduced)
在JeanJacquesGourdin的答案的基础上我想添加一个带有reduce的解决方案,它应该比这两个答案(在撰写本文时)性能更高一些。
我只能鼓励大家进入减少的心态。一旦理解了,使用起来就相当容易了。
const array = [
{eventId: '12345', total: 123},
{eventId: '12347', total: 45},
{eventId: '12345', total: 45},
]
const output = Object.entries(array.reduce((acc, obj) => {
if (!acc[obj.eventId]) {
acc[obj.eventId] = []
}
acc[obj.eventId].push(obj.total)
return acc;
}, {})).map(([eventId, total]) => ({
eventId,
total
}));
console.log(output);
我唯一不喜欢这种方法的是
Object.entries
,它看起来很不合适并且破坏了管道流动。然而,它的性能更高,而且在我看来,也更容易阅读。