1

I want to return an array grouped by the team with gp, win, loss summed up. I'm trying to accomplish this with reduce, however, the totals are not adding up. Here's my code...

const myArr = [
  {team: 'Red', gp: 3, win:2, loss:1},
  {team: 'Black', gp: 3, win:1, loss:2},
  {team: 'Red', gp: 10, win:8, loss:2}
]

let output = myArr.reduce(
  (acc, curr) => {
    acc[curr.team] = {
      gp: acc.gp + curr.gp,
      win: acc.win + curr.win,
      loss: acc.loss + curr.loss
    };
    return acc;
  }, {
    gp: 0,
    win: 0,
    loss: 0
  }
);

console.log(output);

This code returns the array in the format I need, however, the gp, win, loss is not summed up, instead it shows the last data point.

Omid Nikrah
  • 2,444
  • 3
  • 15
  • 30
gvon79
  • 642
  • 3
  • 9
  • 18
  • I played around with groups with sums a while back, here is my StackBlitz in TypeScipt. I might make a JavaScript snippet later if I get the time. https://stackblitz.com/edit/typescript-ezydzv – Adrian Brand Oct 29 '18 at 21:48

3 Answers3

3

You need to take an empty object as accumulator and then you could take the wanted keys for adding.

const
    myArr = [{ team: 'Red', gp: 3, win: 2, loss: 1 }, { team: 'Black', gp: 3, win: 1, loss: 2 }, { team: 'Red', gp: 10, win: 8, loss: 2 }],
    keys = ['gp', 'win', 'loss'],
    output = myArr.reduce((acc, curr) => {
        acc[curr.team] = acc[curr.team] || Object.assign(...keys.map(k => ({ [k]: 0})));
        keys.forEach(k => acc[curr.team][k] += curr[k]);
        return acc;
  }, Object.create(null));

console.log(output);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    Thank you this solved it. I've been learning JS through projects for about 1 1/2 years now and wasn't familiar with Object.assign & Object.create. I'll read up on it, and find tutorials. Thanks again! – gvon79 Oct 29 '18 at 23:13
0

I would reduce the items to a unique set using Set, then map each item to a new object.

const teams = [{team: 'Red', gp: 3, win:2, loss:1},
{team: 'Black', gp: 3, win:1, loss:2},
{team: 'Red', gp: 10, win:8, loss:2}]

let result = [...new Set(teams.map(t => t.team))].map(team => {
  return {
    team,
    gp:   teams.reduce((sum, val) => val.team == team ? sum + val.gp   : sum, 0),
    win:  teams.reduce((sum, val) => val.team == team ? sum + val.win  : sum, 0),
    loss: teams.reduce((sum, val) => val.team == team ? sum + val.loss : sum, 0)
  }
}, [])

console.log(result)
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
0

You could pass an empty array to the accumulator, then using the team property as key, you can check if those values are already defined on the accumulator array, if so then you sum the already defined values with the current ones, otherwise you just take the current values.

const myArr = [
  {team: 'Red', gp: 3, win:2, loss:1},
  {team: 'Black', gp: 3, win:1, loss:2},
  {team: 'Red', gp: 10, win:8, loss:2}
]

let output = myArr.reduce(
  (acc, curr) => {
    acc[curr.team] = {
      gp: acc[curr.team]?.gp ? acc[curr.team].gp + curr.gp : curr.gp,
      win: acc[curr.team]?.win ? acc[curr.team].win + curr.win : curr.win,
      loss: acc[curr.team]?.loss ? acc[curr.team].loss + curr.loss : curr.loss
    };
    return acc;
  }, []
);

console.log(output);
PinguinoSod
  • 85
  • 1
  • 9