Milos
Milos

Reputation: 619

How to group array of objects by common property and put other properties together

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!

Upvotes: 0

Views: 97

Answers (2)

Gpack
Gpack

Reputation: 2193

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

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386654

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

Upvotes: 1

Related Questions