John Doe
John Doe

Reputation: 1172

Merging arrays, why is my input array mutated?

Here is what I'm trying to do :

I have these 2 arrays as inputs. I want to combine them, and merge the objects that have the same "type" property and for these, add the quantities. So, with these 2 arrays below, I have an object with a "type" equal to veggie in each array. The resulting array would have an object with a "type" veggie, and the associated quantity equal to 30 (27+3).

const arr1 = [{"quantity": 27, "type": "veggie"}, {"quantity": 191, "type": "meat"}, {"quantity": 3, "type": "fruit"}];

const arr2 = [{"quantity": 13, "type": "fish"}, {"quantity": 191, "type": "dairy"}, {"quantity": 3, "type": "veggie"}];

const all = [...arr1, ...arr2];

function mergeArrays(arr) {
  const res = arr.reduce(function(acc, curr) {
    const findTagIndex = acc.findIndex((item) => item.type === curr.type);
    if (findTagIndex === -1) {
      acc.push(curr)
    } else {
      acc[findTagIndex].quantity += curr.quantity
    }
    return acc;
    }, []);

    return res;
}

const newArray = mergeArrays(all);

console.log(newArray) // [{quantity: 191, type: "meat"}, {quantity: 30, type: "veggie"}, {quantity: 3, type: "fruit"}, {quantity: 13, type: "fish"}, {quantity: 191, type: "dairy"}];

What I don't understand, and I'm stuck with, is that the merging of arrays seems to mutate arr1. If I console log of arr1 before and after getting the newArray, it will log resp. 27 and 30 veggies. What's going on ?

Any suggestion what I am doing wrong ? How else can I proceed ? I tried several things. I tried with a forEach. Same result.

Upvotes: 0

Views: 64

Answers (2)

StepUp
StepUp

Reputation: 38189

It is possible to use reduce method to calculate sum:

const arr1 = [{"quantity": 27, "type": "veggie"}, {"quantity": 191, "type": "meat"}, {"quantity": 3, "type": "fruit"}];

const arr2 = [{"quantity": 13, "type": "fish"}, {"quantity": 191, "type": "dairy"}, {"quantity": 3, "type": "veggie"}];

const merged = arr1.concat(arr2);

const result = merged.reduce((a, {type, quantity}) => {
    a[type] = a[type] || {type, quantity: 0};
    a[type].quantity += quantity || 0;
    return a;
}, {})

console.log(Object.values(result));

Upvotes: 0

Jonas Wilms
Jonas Wilms

Reputation: 138457

You push the objects from the first array into the other array, thus both arrays hold references to the same objects. You can easily (shallow) copy the objects when pushing:

 acc.push({ ...curr });

Here's how I'd do that (in O(n)):

 const quantityByType = new Map();

 for(const { type, quantity } of [...arr1, ...arr2]) {
   amountByType.set(type, quantity + (quantityByType.get(type) || 0));
 }

 const result = [...quantityByType.entries()]
      .map(([type, quantity]) => ({ type, quantity }));

Upvotes: 1

Related Questions