I am attempting to take an array of results and reduce them into a single array.
The data is:
const data = [
{ profileid: '1', points: 25, winner: true },
{ profileid: '2', points: 15, winner: false },
{ profileid: '3', points: 18, winner: false },
{ profileid: '1', points: 15, winner: true },
{ profileid: '2', points: 18, winner: false },
{ profileid: '3', points: 25, winner: false },
]
I am attempting to sum up all points by userid (I have achieved this) and also sum up the amount of times winner === true in each object
Expected Results
[
{ profileid: '1', points: 40, wins: 1 },
{ profileid: '2', points: 33, wins: 0 },
{ profileid: '3', points: 43, wins: 1 },
]
Currently I am unable to talley the sum of "true" results in each object. Additionally I am returning an object instead of an array.
Snippet
const data = [
{ profileid: '1', points: 25, winner: true },
{ profileid: '2', points: 15, winner: false },
{ profileid: '3', points: 18, winner: false },
{ profileid: '1', points: 15, winner: false },
{ profileid: '2', points: 18, winner: false },
{ profileid: '3', points: 25, winner: true },
]
const result = data.reduce((acc, cur) => ({
...acc,
[cur.profileid]: {
profileid: cur.profileid,
points: cur.points + (acc[cur.profileid] ? acc[cur.profileid].points : 0),
wins: cur.winner
? acc[cur.profile]
? acc[cur.profile].wins + 1
: 0
: acc[cur.profile]
? acc[cur.profile].wins
: 0,
},
}),
[]
)
console.log(result)
Applying the same logic for the points can give something like:
wins: cur.winner ? ((acc[cur.profileid]?.wins || 0) + 1) : (acc[cur.profileid]?.wins || 0),
Were we start by checking if the current winner is true
1 (|| 0) for the first time where wins doesn't existacc[cur.profileid]?.wins (also a fallback if the first time is false)const data = [
{ profileid: '1', points: 25, winner: true },
{ profileid: '2', points: 15, winner: false },
{ profileid: '3', points: 18, winner: false },
{ profileid: '1', points: 15, winner: false },
{ profileid: '2', points: 18, winner: false },
{ profileid: '3', points: 25, winner: true },
]
const result = data.reduce((acc, cur) => ({
...acc,
[cur.profileid]: {
wins: cur.winner ? ((acc[cur.profileid]?.wins || 0) + 1) : (acc[cur.profileid]?.wins || 0),
profileid: cur.profileid,
points: cur.points + (acc[cur.profileid] ? acc[cur.profileid].points : 0),
},
}),
[]
)
console.log(result)
That said, I'd personally prefer a simple for and a single if to get a more readable code:
Please consider this example:
result objdata arraydata if neededpoints and wins valuesconst data = [
{ profileid: '1', points: 25, winner: true },
{ profileid: '2', points: 15, winner: false },
{ profileid: '3', points: 18, winner: false },
{ profileid: '1', points: 15, winner: false },
{ profileid: '2', points: 18, winner: false },
{ profileid: '3', points: 25, winner: true },
];
const result = {};
for (let i in data) {
// Create current profileId object
if (!result[data[i].profileid]) {
result[data[i].profileid] = {
wins: 0,
points: 0,
profileid: +data[i].profileid
};
}
// Bump points/wins values
result[data[i].profileid].points += data[i].points;
result[data[i].profileid].wins += +data[i].winner;
}
console.log(result);
You can sum the wins the same way as you sum the points:
const data = [
{ profileid: '1', points: 25, winner: true },
{ profileid: '2', points: 15, winner: false },
{ profileid: '3', points: 18, winner: false },
{ profileid: '1', points: 15, winner: true },
{ profileid: '2', points: 18, winner: false },
{ profileid: '3', points: 25, winner: true },
]
const result = data.reduce((acc, cur) => ({
...acc,
[cur.profileid]: {
profileid: cur.profileid,
points: cur.points + (acc[cur.profileid] ? acc[cur.profileid].points : 0),
wins: cur.winner + (acc[cur.profileid] ? acc[cur.profileid].wins : 0)
},
}),
[]
)
console.log(result)
You can also simplify wins like this:
wins: !!(acc[cur.profileid]?.wins) + cur.winner
In case acc[cur.profileid]?.wins returns undefined,
you can convert it to a Boolean by !! or Boolean() to avoid getting NaN