Reputation: 2029
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.
Upvotes: 1
Views: 1317
Reputation: 4412
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:
Upvotes: 4
Reputation: 386600
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>');
Upvotes: 1
Reputation: 956
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}]
Upvotes: 1
Reputation: 1
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>
Upvotes: 0