Reputation: 582
I have an array of objects, where I'd like to merge some objects if certain data matches. Here is the array:
0: {name: "1", qty: "3", measurement: "Tbsp"}
1: {name: "paprika", qty: "2", measurement: "Tbsp"}
2: {name: "onion", qty: "1", measurement: "cup"}
3: {name: "tomatoes", qty: "16", measurement: "oz"}
4: {name: "tomatoes", qty: "16", measurement: "oz"}
I'd like to match based on the name and measurement keys. I.e. if the name
is the same AND the measurement
is the same, then combine the object and total the qty
, where the resulting object would be:
0: {name: "1", qty: "3", measurement: "Tbsp"}
1: {name: "paprika", qty: "2", measurement: "Tbsp"}
2: {name: "onion", qty: "1", measurement: "cup"}
3: {name: "tomatoes", qty: "32", measurement: "oz"}
I've tried it a few ways using .includes()
and .some()
but haven't managed with any success yet. Any help appreciated.
Upvotes: 0
Views: 32
Reputation: 171679
Approach using a Map and concatenating the name and measurement to create the unique keys so they look like "tomatoes|oz"
const groupItems = (arr) => {
const m = new Map;
arr.forEach(o => {
const k = `${o.name}|${o.measurement}`;
// if the key already exists just add current qty
// otherwise set new entry using current object
m.has(k) ? m.get(k).qty += o.qty : m.set(k, {...o});
});
return [...m.values()];
}
console.log(groupItems(data))
<script>
const data=[{name:"1",qty:3,measurement:"Tbsp"},{name:"paprika",qty:2,measurement:"Tbsp"},{name:"onion",qty:1,measurement:"cup"},{name:"tomatoes",qty:16,measurement:"oz"},{name:"tomatoes",qty:16,measurement:"oz"}];
</script>
Upvotes: 0
Reputation: 16576
This is a good use case for the array reduce
method. The following can be used to determine if our accumulator already has the desired item. If so, add the quantity. If not, push the item onto the accumulator array.
const items = [
{name: "1", qty: 3, measurement: "Tbsp"},
{name: "paprika", qty: 2, measurement: "Tbsp"},
{name: "onion", qty: 1, measurement: "cup"},
{name: "tomatoes", qty: 16, measurement: "oz"},
{name: "tomatoes", qty: 16, measurement: "oz"}
];
const combined = items.reduce((acc, el) => {
const found = acc.find(item => item.name === el.name && item.measurement === el.measurement);
if (found) {
found.qty += el.qty;
} else {
acc.push(el);
}
return acc;
}, []);
console.log(combined);
Upvotes: 1