javascript - Reduce array of objects by user_id and sum certain values - Stack Overflow

I have an array of objects that looks like this: "data": [{ "workout_id": 1, "

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
Add a ment  | 

3 Answers 3

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);

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745518506a4631145.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信