Cain Nuke
Cain Nuke

Reputation: 3079

Combine 2 array of objects if matches are found

I have these 2 arrays of objects:

const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];

I want to combine them but at the same time summing their values in qty when they have the same id. This is the expected output:

[{"id":"pear","qty":7},{"id":"apple","qty":2},{"id":"lemon","qty":1}];

I tried this but it only keeps the first object:

const newArray = arr1.map((obj) => {
  const secondArrayObj = arr2.find((obj2) => obj2.id === obj.id);
  if (secondArrayObj) {
    return {...secondArrayObj, ...obj}
  }
  return null;
}).filter((obj) => obj != null);
console.log(newArray); 

What is the best approach here?

Upvotes: 0

Views: 76

Answers (3)

Phil
Phil

Reputation: 164766

  1. Combine both arrays
  2. Reduce them to a map keyed by id and value being the sum of qty
  3. Turn that object back into an array using Object.entries()
  4. Map that back to an array of objects

const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];

const newArray = [
  ...arr1
    .concat(arr2)
    .reduce(
      (map, { id, qty }) => map.set(id, qty + (map.get(id) ?? 0)),
      new Map()
    ),
].map(([id, qty]) => ({ id, qty }));

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

Upvotes: 0

Peter Thoeny
Peter Thoeny

Reputation: 7616

There are several ways to skin the cat. Here is one that uses an intermediate sums object, which performs well with large arrays:

const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];

let sums = {};
arr1.concat(arr2).forEach(obj => {
  if(!sums[obj.id]) {
    sums[obj.id] = 0;
  }
  sums[obj.id] += obj.qty;
});
let arr3 = Object.keys(sums).map(id => { return {id: id, qty: sums[id]}; });
console.log(arr3);

Output:

[
  {
    "id": "pear",
    "qty": 7
  },
  {
    "id": "apple",
    "qty": 2
  },
  {
    "id": "lemon",
    "qty": 1
  }
]

Upvotes: 1

flyingfox
flyingfox

Reputation: 13506

For your code,the reason is that you are using Array.map(),it will only covnert arr1 to another array,and will not merge arr2

To solve it,we can do it via Array.reduce() and Array.filter()

const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];

let arr3 = [...arr1,...arr2]
arr3 = arr3.reduce((a,v) => {
  let obj = a.find(i => i.id === v.id)
  if(obj){
   obj.qty += v.qty 
   }else{
    a.push(v) 
   }
  return a
},[])
console.log(arr3)

Upvotes: 1

Related Questions