0

I have an array of objects like this

const statuses = [
  {time: '21/1/1990', 'Status.sold': 8848},
  {time: '21/1/1990', 'Status.reserved': 8804},
  {time: '21/1/1991', 'Status.reserved': 8756},
  {time: '21/1/1991', 'Status.sold': 8732},
  {time: '21/1/1992', 'Status.killed': 8691},
  {time: '21/1/1992', 'Status.sold': 8620},
  {time: '21/1/1993', 'Status.held': 8511},
  {time: '21/1/1993', 'Status.killed': 8511},
  {time: '21/1/1994', 'Status.sold': 8498},
];

and what I am trying to achieve is to put all Status. properties together and grouped by the time property, which is common for all objects. So the final result will be like this

const statuses = [
  {time: '21/1/1990', sold: 8848, killed: 0, reserved: 8804, held: 0},
  {time: '21/1/1991', sold: 8732, killed: 0, reserved: 8756, held: 0},
  {time: '21/1/1992', sold: 8620, killed: 8691, reserved: 0, held: 0},
  {time: '21/1/1993', sold: 0, killed: 8511, reserved: 0, held: 8511},
  {time: '21/1/1994', sold: 8498, killed: 0, reserved: 0, held: 0},
];

I have tried something like this

const result = statuses.map((obj) => {
   return { ...obj, 
      sold: obj['Status.sold'] ? obj['Status.sold'] : 0,
      reserved: obj['Status.reserved'] ? obj['Status.reserved'] : 0,
      killed: obj['Status.killed'] ? obj['Status.killed'] : 0,
      held: obj['Status.held'] ? obj['Status.held'] : 0
   };
});

but I'm not sure how to group them by time. How can I combine reduce method with this code? Thanks in advance!

Milos
  • 569
  • 3
  • 8
  • 21
  • 1
    use `reduce` function – Vivek Bani Jun 03 '21 at 11:38
  • 1
    Take a look here: [Most efficient method to groupby on an array of objects](https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects]) – alexP Jun 03 '21 at 11:44

2 Answers2

1

You could take an object for grouping by time.

const
    statuses = [{ time: '21/1/1990', 'Status.sold': 8848 }, { time: '21/1/1990', 'Status.reserved': 8804 }, { time: '21/1/1991', 'Status.reserved': 8756 }, { time: '21/1/1991', 'Status.sold': 8732 }, { time: '21/1/1992', 'Status.killed': 8691 }, { time: '21/1/1992', 'Status.sold': 8620 }, { time: '21/1/1993', 'Status.held': 8511 }, { time: '21/1/1993', 'Status.killed': 8511 }, { time: '21/1/1994', 'Status.sold': 8498 }],
    result = Object.values(statuses.reduce((r, { time, ...o }) => {
        r[time] ??= { time, sold: 0, killed: 0, reserved: 0, held: 0 };
        Object.entries(o).forEach(([k, v]) => r[time][k.slice(7)] += v);
        return r;
    }, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Can you please explain to me why do we need `k.slice(7)` ? Thanks! – Milos Jun 03 '21 at 11:51
  • this is to get only the word `'killed'` from `'Status.sold'`, for example. maybe you wante the complete string or a nested approach by using the splitted values ...? – Nina Scholz Jun 03 '21 at 11:54
1

Try this:

const statuses = [
  {time: '21/1/1990', 'Status.sold': 8848},
  {time: '21/1/1990', 'Status.reserved': 8804},
  {time: '21/1/1991', 'Status.reserved': 8756},
  {time: '21/1/1991', 'Status.sold': 8732},
  {time: '21/1/1992', 'Status.killed': 8691},
  {time: '21/1/1992', 'Status.sold': 8620},
  {time: '21/1/1993', 'Status.held': 8511},
  {time: '21/1/1993', 'Status.killed': 8511},
  {time: '21/1/1994', 'Status.sold': 8498},
];

const result = [];

let obj = {};
for (let i = 0; i < statuses.length; i++) {
  const status = statuses[i];
  if (status.time != obj.time) {
    if (i != 0) result.push(obj); 
    obj = {
      time: status.time,
      sold: 0,
      reserved: 0,
      killed: 0,
      held: 0,
    }
  }
  if (status['Status.sold']) obj.sold += status['Status.sold'];
  if (status['Status.reserved']) obj.reserved += status['Status.reserved'];
  if (status['Status.killed']) obj.killed += status['Status.killed'];
  if (status['Status.held']) obj.held += status['Status.held'];
}
result.push(obj);
console.log(result);
Gpack
  • 1,878
  • 3
  • 18
  • 45