0

I have array of object

 const users = [
     { group: 'editor', name: 'Adam', age: 23 },
     { group: 'editor', name: 'John', age: 28 },
     { group: 'editor', name: 'William', age: 34 },
     { group: 'admin', name: 'Oliver', age: 28' }
 ];

Expected result:

//sum
 sumAge = {
 editor: 85,  // 23+34+28
 admin: 28    // 28
}

//average
avgAge = {
   editor: 28.33,  // (85) / 3
   admin: 28    //(28)/1
}

I use reduce() method to group the objects in an array by 'group' and calculate sum:

let sumAge = users.reduce((group, age) => {
    group[age.group] = (group[age.group] || 0) + age.age || 1;
    return group;
}, {})
console.log('sumAge', sumAge); // sumAge: {editor: 85, admin: 28} 
done!

How to group object of Array by key 'group' and calculate average?. I tried:

let ageAvg= users.reduce((group, age) => {
      if (!group[age.group]) {
      group[age.group] = { ...age, count: 1 }
         return group;
      }
      group[age.group].age+= age.age;
      group[age.group].count += 1;
      return group;
      }, {})
const result = Object.keys(ageAvg).map(function(x){
     const item  = ageAvg[x];
     return {
         group: item.group,
         ageAvg: item.age/item.count,
     }
 })
console.log('result',result);
/*
result=[
    {group: "editor", ageAvg: 28.33}
    {group: "admin", ageAvg: 28}
]

But Expected result:

result = {
   editor: 28.33,  // (85) / 3
   admin: 28    //(28)/1
}
2
  • If you want a single object, map() will not work for you. And if you want just group: average, then your return inside that map doesn't match that at all Commented Aug 12, 2020 at 17:05
  • Otherwise, reduce() the result of that map to the single object you want Commented Aug 12, 2020 at 17:05

1 Answer 1

3

You can reduce to combine age values per group, then map to compute averages per key and convert back to an object with Object.fromEntries:

const users = [
  { group: 'editor', name: 'Adam', age: 23 },
  { group: 'editor', name: 'John', age: 28 },
  { group: 'editor', name: 'William', age: 34 },
  { group: 'admin', name: 'Oliver', age: 28 }
];

const grouped = users.reduce((a, e) => {
  if (!a[e.group]) {
    a[e.group] = [];
  }
  
  a[e.group].push(e.age);
  return a;
}, {});

const avgs = Object.fromEntries(
  Object.entries(grouped).map(([k, v]) => [
    k, v.reduce((a, e) => a + e, 0) / v.length
  ])
);

console.log(avgs);

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for replying to my post... I don't understand code : const avgs = Object.fromEntries( Object.entries(grouped).map(([k, v]) => [ k, v.reduce((a, e) => a + e, 0) / v.length ]) );
What about it don't you understand? Object.entries dumps an object into an array of pairs, map's callback takes the average of each array and Object.fromEntries converts the entry pairs back into an object. Please see the docs for each function, and/or split it into multiple intermediate variables and print each one as you go.
@ggorlen - you point out this is a duplicate of minhminh's previous post; how about putting this answer there and help to close this dupe?
@StephenP I didn't realize it was a dupe until after I'd posted my answer. I'll vote to delete whichever post gets closed first.
@ggorlen. OP is posting this question multiple times - in this question i answered exactly that was mentioned in the expected output here.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.