Denny Rachmadi
Denny Rachmadi

Reputation: 163

group array of objects

Hi guys i've question about how to group by key id value and do sum on ( key harga value and key qty value) below are the array of objects:

order: [
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  },
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  }
]

what i wan't to achieve is like this :

order:[
   {
     id: 4,
     idkatg: 2,
     kategori: 'minuman',
     nmprod: 'es mambo',
     harga: 14000,
     qty: 2
   }
]

is there any solution using lodash maybe ?

Upvotes: 0

Views: 116

Answers (5)

Koushik Chatterjee
Koushik Chatterjee

Reputation: 4175

Since you have tagged lodash this is as simple as (cleaner) this:

_(order).groupBy('id').map(a=>({...a[0], harga: _.sumBy(a, 'harga'), qty: _.sumBy(a, 'qty')})).value()

You can use reduce instead of 2 sumBy if you want to do the sum in a single iteration (however using lodash you are actually not looking for faster solution with less iterations anyway

let order = [
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  },
  {
    id: 3,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 2000,
    qty: 1
  },
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  },
  {
    id: 5,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 6000,
    qty: 1
  },
  {
    id: 5,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 9000,
    qty: 1
  }
];

let res =_(order).groupBy('id').map(a=>({...a[0], harga: _.sumBy(a, 'harga'), qty: _.sumBy(a, 'qty')})).value()

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
https://stackoverflow.com/questions/52475365/group-array-of-objects/52475751#

There are Vanilla JS solution (and faster) for every lodash solution. But that's completely depend on you what you want, you are already using lodash or not. performance is really matter or cleanest code and maintainability and handling all the corner cases and some other factors.

Upvotes: 1

Hassan Imam
Hassan Imam

Reputation: 22574

You can use groupBy based on the id key and then using map reduce using sumBy & fromPairs operation.

let order = [ { id: 4, idkatg: 2, kategori: 'minuman', nmprod: 'es mambo', harga: 8000, qty: 1 }, { id: 4, idkatg: 2, kategori: 'minuman', nmprod: 'es mambo', harga: 8000, qty: 1 } ],
    result = _(order).groupBy('id').map((o,k) =>
      ({...o[0], ..._.fromPairs(_(['qty','harga']).map(k => [k,_.sumBy(o,k)]).value())})).value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Upvotes: 1

protoproto
protoproto

Reputation: 2099

You can use 2 pure for loops to set:

var order = [
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  },
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  },
  {
    id: 5,
    idkatg: 3,
    kategori: '5 minuman',
    nmprod: '5 es mambo',
    harga: 5000,
    qty: 3
  },
  {
    id: 5,
    idkatg: 3,
    kategori: '5 minuman',
    nmprod: '5 es mambo',
    harga: 4000,
    qty: 2
  },
  {
    id: 6,
    idkatg: 4,
    kategori: '6 minuman',
    nmprod: '6 es mambo',
    harga: 6000,
    qty: 2
  }
];

var result = [];
result.push(order[0]);
for (var i=1; i<order.length; i++){
  //compare object order[i] with order[0] ... order[n]
  var flagExist = false;
  for (var j=0; j<i; j++){
    if(order[j].id === order[i].id){
      flagExist = true;
      //set for object old, with new qty and harga
      order[j].qty = order[i].qty + order[j].qty;
      order[j].harga = order[i].harga + order[j].harga;
      break;
    }
  }
  if (flagExist == false)
    result.push(order[i]);
}
console.log(result);

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386883

You could reduce the object and find the object with the same id, then update. Otherwise push the actual object to the result set.

If needed, you could take a sloppy copy with

r.push(Object.assign({}, o));

var order = [{ id: 4, idkatg: 2, kategori: 'minuman', nmprod: 'es mambo', harga: 8000, qty: 1 }, { id: 4, idkatg: 2, kategori: 'minuman', nmprod: 'es mambo', harga: 8000, qty: 1 }];

order = order.reduce((r, o) => {
   var temp = r.find(({ id }) => id === o.id);
   if (temp) {
       ['harga', 'qty'].forEach(k => temp[k] += o[k]);
   } else {
       r.push(o);
   }
   return r;
}, []);

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

Upvotes: 1

Rafal Wiliński
Rafal Wiliński

Reputation: 2390

Try this:

const order = [
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  },
  {
    id: 4,
    idkatg: 2,
    kategori: 'minuman',
    nmprod: 'es mambo',
    harga: 8000,
    qty: 1
  }
];

const newOrder = [];

for (const index in order) {
  const item = order[index];
  const itemInNewOrder = newOrder.filter(i => i.id === item.id)[0];

  if (itemInNewOrder) {
    itemInNewOrder.harga += item.harga;
  } else {
    newOrder.push(item);
  }
}

console.log(newOrder);

This question is similar to: Merge objects with the same id but sum values of the objects

Upvotes: 1

Related Questions