简体   繁体   中英

Add and combine duplicates in array of objects with lodash with specific conditions

Say I have a sorted array of objects like this:

[
  {name: 'item1', quantity: 5},
  {name: 'item1', quantity: 8},
  {name: 'item2', quantity: 6},
  {name: 'item2', quantity: 3},
  {name: 'item3', quantity: 1},
  {name: 'item3', quantity: 1},
]

I want to add up the values of items which have quantities > 1 and combine them so I get this:

[
  {name: 'item1', quantity: 13},
  {name: 'item2', quantity: 9},
  {name: 'item3', quantity: 1},
  {name: 'item3', quantity: 1},
]

Is there a quick single or chain of lodash methods that can achieve this? I was thinking to use _.map but it doesn't give you previous item, so I'd have to use a variable outside the _.map scope to keep that value. Seeing if I can do this with lodash since I'm already using it for other methods and not write extra lines of code.

If the extra condition is not possible, then combining and adding all items will have to do.

This is my attempt using only lodash:

 var source = [ {name: 'item1', quantity: 5}, {name: 'item1', quantity: 8}, {name: 'item2', quantity: 6}, {name: 'item2', quantity: 3}, {name: 'item3', quantity: 1}, {name: 'item3', quantity: 1}, ]; var predicate = function (e) { return e.quantity > 1; }; var result = _.chain(source) .filter(predicate) .groupBy(function (e) { return e.name; }) .map(function (group) { return _.reduce(group, function (current, next) { return { name: next.name, quantity: current.quantity + next.quantity }; }); }) .union(_.filter(source, function (e) { return !predicate(e); })) .value(); document.getElementById("output").textContent = JSON.stringify(result, 0, 2); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script> <pre id="output"></pre> 

Not sure if this is the most efficient way, as I'm not deeply familiar with lodash. Basically, the idea is this:

  1. Get the elements with quantity > 1
  2. Group by name
  3. Produce sums for each name
  4. Union with the elements with quantity <= 1

Fiddle

Another solution in plain Javascript with a single loop.

 var data = [{ name: 'item1', quantity: 5 }, { name: 'item1', quantity: 8 }, { name: 'item2', quantity: 6 }, { name: 'item2', quantity: 3 }, { name: 'item3', quantity: 1 }, { name: 'item3', quantity: 1 }], combined = function (array) { var r = []; array.forEach(function (a, i) { if (a.quantity === 1) { r.push(a); return; } if (!this[a.name]) { this[a.name] = { name: a.name, quantity: 0 }; r.push(this[a.name]); } this[a.name].quantity += a.quantity; }, {}); return r; }(data); document.write('<pre>' + JSON.stringify(combined, 0, 4) + '</pre>'); 

You can use Array.prototype.forEach() , for loop

 var arr = [ {name: 'item1', quantity: 5}, {name: 'item1', quantity: 8}, {name: 'item2', quantity: 6}, {name: 'item2', quantity: 3}, {name: 'item3', quantity: 1}, {name: 'item3', quantity: 1}, ]; var res = []; arr.forEach(function(item, index) { if (res.length === 0 || !res.some(function(elem) {return elem.name === item.name}) || item["quantity"] === 1 ) { res.push(item) } else { for (var i = 0; i < res.length; i++) { if (res[i]["name"] === item["name"] && (res[i]["quantity"] !== 1 && item["quantity"] !== 1)) { res[i]["quantity"] += item["quantity"] } } } }); document.querySelector("pre").textContent = JSON.stringify(res, null, 2) 
 <pre></pre> 

Here is a pure lodash-ian solution :)
It uses chain , reduce , toPairs , map and 1 temporary variable to do the job.

items = [
  {name: 'item1', quantity: 5},
  {name: 'item1', quantity: 8},
  {name: 'item2', quantity: 6},
  {name: 'item2', quantity: 3},
  {name: 'item3', quantity: 1},
  {name: 'item3', quantity: 1}
];

summary = _.chain(items).reduce(function(acc, i) {
  if (i.quantity > 0) {
    acc[i.name] = (acc[i.name] || 0) + i.quantity;
  }
  return acc;
}, {}).toPairs().map(function(x) {
  var tmp = {};
  tmp[x[0]] = x[1];
  return tmp;
}).value();

console.log(JSON.stringify(summary));
// Outputs:  [{"item1":13},{"item2":9},{"item3":2}]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM