acd37
acd37

Reputation: 582

Merging JavaScript objects in an array where data matches

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

Answers (2)

charlietfl
charlietfl

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

Nick
Nick

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

Related Questions