最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin0浏览0评论

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

发布评论

评论列表(0)

  1. 暂无评论