I have an array of objects that looks like this:
"data": [
{ "workout_id": 1, "user_id": 1, "shotLocation": 27, "shotAttempts": 20,"shotsMade": 19, "id": 1 },
{ "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 2 },
{ "workout_id": 2, "user_id": 1, "shotLocation": 10, "shotAttempts": 10, "shotsMade": 7, "id": 3 },
{ "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 29, "id": 4 },
{ "workout_id": 3, "user_id": 5, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 5 },
{ "workout_id": 4, "user_id": 6, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 15, "id": 6 },
{ "workout_id": 4, "user_id": 6, "shotLocation": 2, "shotAttempts": 20, "shotsMade": 14, "id": 7 }
]
I would like to create a new array of objects where I
- reduce the user_ids to each unique user
- then calculate the total shotAttempts and shotsMade for each user
like this:
"dataTotals" : [
{"id": 1, "user_id": 1, "shotAttempts": 90, "shotsMade": 64}
{"id": 2, "user_id": 5, "shotAttempts": 10, "shotsMade": 9}
{"id": 3, "user_id": 6, "shotAttempts": 50, "shotsMade": 29}
I plan on iterating over this new array of objects with a .map function to populate a leaderboard as more users record their data.
I've tried several different ways to achieve this based on what I've read about the .map and .reduce methods, as well as searching here and found something that's close, but it returns an object as indicated below.
like this:
// create new object to store results in
let newObj = {};
// loop through user objects
this.state.shotlogs.forEach(function(shotlog){
// check if user_id has already been added to newObj
if(!newObj[shotlog.user_id]){
// If it is the first time seeing this user_id
// we need to add shots attempted and shots made to prevent errors
newObj[shotlog.user_id] = {};
newObj[shotlog.user_id]['user_id'] = shotlog.user_id;
newObj[shotlog.user_id]['shotAttempts'] = 0;
newObj[shotlog.user_id]['shotsMade'] = 0;
}
// add shots attempted and made to newObj for this user
newObj[shotlog.user_id]['shotAttempts'] += shotlog.shotAttempts
newObj[shotlog.user_id]['shotsMade'] += shotlog.shotsMade
})
but this returns an object that looks like this and not an array of objects like above:
{
1: {user_id: 1, shotAttempts: 70, shotsMade: 64}
5: {user_id: 5, shotAttempts: 10, shotsMade: 9}
6: {user_id: 6, shotAttempts: 50, shotsMade: 29}
}
Any help for this new coder is greatly appreciated!!
I have an array of objects that looks like this:
"data": [
{ "workout_id": 1, "user_id": 1, "shotLocation": 27, "shotAttempts": 20,"shotsMade": 19, "id": 1 },
{ "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 2 },
{ "workout_id": 2, "user_id": 1, "shotLocation": 10, "shotAttempts": 10, "shotsMade": 7, "id": 3 },
{ "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 29, "id": 4 },
{ "workout_id": 3, "user_id": 5, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 5 },
{ "workout_id": 4, "user_id": 6, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 15, "id": 6 },
{ "workout_id": 4, "user_id": 6, "shotLocation": 2, "shotAttempts": 20, "shotsMade": 14, "id": 7 }
]
I would like to create a new array of objects where I
- reduce the user_ids to each unique user
- then calculate the total shotAttempts and shotsMade for each user
like this:
"dataTotals" : [
{"id": 1, "user_id": 1, "shotAttempts": 90, "shotsMade": 64}
{"id": 2, "user_id": 5, "shotAttempts": 10, "shotsMade": 9}
{"id": 3, "user_id": 6, "shotAttempts": 50, "shotsMade": 29}
I plan on iterating over this new array of objects with a .map function to populate a leaderboard as more users record their data.
I've tried several different ways to achieve this based on what I've read about the .map and .reduce methods, as well as searching here and found something that's close, but it returns an object as indicated below.
like this:
// create new object to store results in
let newObj = {};
// loop through user objects
this.state.shotlogs.forEach(function(shotlog){
// check if user_id has already been added to newObj
if(!newObj[shotlog.user_id]){
// If it is the first time seeing this user_id
// we need to add shots attempted and shots made to prevent errors
newObj[shotlog.user_id] = {};
newObj[shotlog.user_id]['user_id'] = shotlog.user_id;
newObj[shotlog.user_id]['shotAttempts'] = 0;
newObj[shotlog.user_id]['shotsMade'] = 0;
}
// add shots attempted and made to newObj for this user
newObj[shotlog.user_id]['shotAttempts'] += shotlog.shotAttempts
newObj[shotlog.user_id]['shotsMade'] += shotlog.shotsMade
})
but this returns an object that looks like this and not an array of objects like above:
{
1: {user_id: 1, shotAttempts: 70, shotsMade: 64}
5: {user_id: 5, shotAttempts: 10, shotsMade: 9}
6: {user_id: 6, shotAttempts: 50, shotsMade: 29}
}
Any help for this new coder is greatly appreciated!!
Share Improve this question edited Dec 18, 2018 at 4:57 bnilsen asked Dec 18, 2018 at 4:51 bnilsenbnilsen 311 silver badge4 bronze badges 2-
1
Use
Object.values(newObj)
to get its values as an array. – slider Commented Dec 18, 2018 at 4:56 - 2 That seems to be exactly what I need! Thank you!!! – bnilsen Commented Dec 18, 2018 at 4:59
3 Answers
Reset to default 3
const data = [
{ workout_id: 1, user_id: 1, shotLocation: 27, shotAttempts: 20, shotsMade: 19, id: 1 },
{ workout_id: 2, user_id: 1, shotLocation: 1, shotAttempts: 10, shotsMade: 9, id: 2 },
{ workout_id: 2, user_id: 1, shotLocation: 10, shotAttempts: 10, shotsMade: 7, id: 3 },
{ workout_id: 2, user_id: 1, shotLocation: 1, shotAttempts: 30, shotsMade: 29, id: 4 },
{ workout_id: 3, user_id: 5, shotLocation: 1, shotAttempts: 10, shotsMade: 9, id: 5 },
{ workout_id: 4, user_id: 6, shotLocation: 1, shotAttempts: 30, shotsMade: 15, id: 6 },
{ workout_id: 4, user_id: 6, shotLocation: 2, shotAttempts: 20, shotsMade: 14, id: 7 }
];
const shooters = data.reduce(
(results, current) => ({
...results,
[current.user_id]: {
user_id: current.user_id,
shotAttempts: current.shotAttempts + (results[current.user_id] ? results[current.user_id].shotAttempts : 0),
shotsMade: current.shotsMade + (results[current.user_id] ? results[current.user_id].shotsMade : 0)
}
}),
{}
);
console.log(shooters);
You can use Array.reduce
, Object.values
with ES6 destructuring and solve this in a concise manner:
const data = [{ "workout_id": 1, "user_id": 1, "shotLocation": 27, "shotAttempts": 20, "shotsMade": 19, "id": 1 }, { "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 2 }, { "workout_id": 2, "user_id": 1, "shotLocation": 10, "shotAttempts": 10, "shotsMade": 7, "id": 3 }, { "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 29, "id": 4 }, { "workout_id": 3, "user_id": 5, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 5 }, { "workout_id": 4, "user_id": 6, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 15, "id": 6 }, { "workout_id": 4, "user_id": 6, "shotLocation": 2, "shotAttempts": 20, "shotsMade": 14, "id": 7 } ]
const result = data.reduce((r,{workout_id, user_id, shotAttempts, shotsMade}) => {
r[user_id] = r[user_id] || {id: workout_id, user_id, shotAttempts: 0, shotsMade: 0}
r[user_id].shotAttempts += shotAttempts
r[user_id].shotsMade += shotsMade
return r
}, {})
console.log(Object.values(result))
You can use Array.prototype.reduce()
Code:
const data = [{ "workout_id": 1, "user_id": 1, "shotLocation": 27, "shotAttempts": 20,"shotsMade": 19, "id": 1 },{ "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 2 },{ "workout_id": 2, "user_id": 1, "shotLocation": 10, "shotAttempts": 10, "shotsMade": 7, "id": 3 },{ "workout_id": 2, "user_id": 1, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 29, "id": 4 },{ "workout_id": 3, "user_id": 5, "shotLocation": 1, "shotAttempts": 10, "shotsMade": 9, "id": 5 },{ "workout_id": 4, "user_id": 6, "shotLocation": 1, "shotAttempts": 30, "shotsMade": 15, "id": 6 },{ "workout_id": 4, "user_id": 6, "shotLocation": 2, "shotAttempts": 20, "shotsMade": 14, "id": 7 }];
const dataTotals = Object.values(data.reduce((a, c) => {
if (!a[c.user_id]) {
a[c.user_id] = {
id: c.workout_id,
user_id: c.user_id,
shotAttempts: c.shotAttempts,
shotsMade: c.shotsMade
};
} else {
a[c.user_id].shotAttempts += c.shotAttempts;
a[c.user_id].shotsMade += c.shotsMade;
}
return a;
}, {}));
console.log(dataTotals);