ES6 nested grouping with sum

I have an array like this:

[{
   id: 1,
   amount: 10,
   date: '21/01/2017'
},{
   id: 1,
   amount: 10,
   date: '21/01/2017'
},{
   id: 1,
   amount: 30,
   date: '22/01/2017'
},{
   id: 2,
   amount: 10,
   date: '21/01/2017'
},]

And I would like this to be output as:

{
  '21/01/2017': {
    1: {
      amount: 20
    },
    2: {
      amount: 10
    }
  },
  '22/01/2017': {
    1: {
      amount: 30
    }
  }
}

Essentially grouping by data, nested grouping by id, when summing the corresponding amounts.

So far, I have tried to use shortening, and looked at the lodash functions, but was unsuccessful. Zoom out makes it easy to group and summarize one leg, but I can't find an elegant way to create a second level. I created a sandbox to demonstrate:

https://codesandbox.io/s/woj9xz6nq5

const dataToConsolidate = [{
  id: 1,
  amount: 10,
  date: '21/01/2017'
}, {
  id: 1,
  amount: 10,
  date: '21/01/2017'
}, {
  id: 1,
  amount: 30,
  date: '22/01/2017'
}, {
  id: 2,
  amount: 10,
  date: '21/01/2017'
},]

export const consolidate = (data) => {
  const result = data.reduce(function (res, obj) {

    (!(obj.date in res)) ?
      res.__array.push(res[obj.date] = obj) :
      res[obj.date].amount += obj.amount;

    return res;
  }, { __array: [] });

  return result;
};

console.log(consolidate(dataToConsolidate))
Run codeHide result
+4
source share
4 answers

Here's an ES6-y solution using reduce:

const initial = [{ id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 30, date: '22/01/2017' }, { id: 2, amount: 10, date: '21/01/2017' }];

const parse = obj => obj.reduce((final, { date, id, amount }) => {
  let group = final[date] = final[date] || {};
  group[id] = group[id] || { amount: 0 };
  group[id].amount += amount;
  return final;
}, {});

const final = parse(initial);
console.log(final);
Run codeHide result

/ date, id amount.

+3

- .

var array = [{ id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 30, date: '22/01/2017' }, { id: 2, amount: 10, date: '21/01/2017' }],
    result = {};

array.forEach(function (o) {
    result[o.date] = result[o.date] || {};
    result[o.date][o.id] = result[o.date][o.id] || { amount: 0 };
    result[o.date][o.id].amount += o.amount;
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Hide result
+5

As a fan of the Ramda library (disclaimer: I am one of the authors), I could use it to make everything more explicit:

const {pipe, groupBy, prop, map, pluck, sum} = R

const data = [
  {"amount": 10, "date": "21/01/2017", "id": 1}, 
  {"amount": 10, "date": "21/01/2017", "id": 1}, 
  {"amount": 30, "date": "22/01/2017", "id": 1}, 
  {"amount": 10, "date": "21/01/2017", "id": 2}
]

const consolidate = pipe(
  groupBy(prop('date')),
  map(groupBy(prop('id'))),
  map(map(pluck('amount'))),
  map(map(sum))
)

console.log(consolidate(data))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Run codeHide result

Of course, using the library just to solve this problem simply went too far when something like the solution from @NinaSholz was just fine. But if you find a few places where this might help, it might be worth a look at something like this.

+3
source

you can do it through _.groupBy:

const res = _.chain(data)
    .groupBy('date')
    .mapValues(dateObj => _.chain(dateObj)
        .groupBy('id')
        .mapValues(idObj => ({ amount: _.sumBy(idObj, 'amount') }))
        .value()
     )
     .value();
0
source

Source: https://habr.com/ru/post/1690093/


All Articles