0

I'm working on a project where I've got 2 object arrays and the following are the various cases the data can be in.

// Case 1
var arr1=[{id:1,quantity:10}]
var arr2=[{id:1,quantity:10},{id:2,quantity:20}]

// Case 2
var arr1=[]
var arr2=[{id:1,quantity:10},{id:2,quantity:20}]

// Case 3
var arr1=[{id:1,quantity:12}]
var arr2=[{id:1,quantity:10},{id:2,quantity:20}]

// Case 4
var arr1=[{id:1,quantity:10},{id:1,quantity:20}]
var arr2=[{id:1,quantity:10}]

So, the array1 might be empty, might have one of the objects from array2 or both the objects of array2 with a different quantity value.

I'd like to update the main array or arr1 based on arr2 but don't want to completely swipe arr1 with arr2 with arr1=arr2 kind of solution. arr1 should update quantity based on arr2 and add or remove based on the same thing.

5
  • Can you give a before/after example? Commented Oct 17, 2017 at 20:19
  • How can the code both update and add and remove elements at the same time? Commented Oct 17, 2017 at 20:27
  • Can you explain how the result would be different from arr1 = arr2? Commented Oct 17, 2017 at 20:31
  • @trincot because I don't want the api that the data comes from to replace everything stored in the array, causing the views that use the array to go to an empty state and then fill up again, it'd be better if I had a solution as stated above Commented Oct 17, 2017 at 20:35
  • 2
    I am not sure I understand: if the replacing of the array content happens synchronously, there would be no moment at which a view would see the array being empty. I do understand however that assigning a new array to the variable will not affect already existing references to the previous array. To deal with that you need to mutate the array (as proposed in my answer). Commented Oct 17, 2017 at 20:39

2 Answers 2

1

If arr1 = arr2 would be a solution, except that you want to mutate arr1 instead of replacing it, then consider using splice:

var arr1=[{id:0,quantity:1},{id:2,quantity:12},{id:3,quantity:9}],
    arr2=[{id:1,quantity:10},{id:2,quantity:20}];

arr1.splice(0, arr1.length, ...arr2);

console.log(arr1);

If your concern is that the objects in arr1 should not be replaced when their id exists in arr2, but be mutated (keeping their references), then I would suggest:

var arr1=[{id:0,quantity:1},{id:2,quantity:12},{id:3,quantity:9}],
    arr2=[{id:1,quantity:10},{id:2,quantity:20}];
// key both arrays by id in Maps
var mp1 = new Map(arr1.map(obj => [obj.id, obj])),
    mp2 = new Map(arr2.map(obj => [obj.id, obj]));
// traverse arr1 from right to left so deletions will not affect the loop
arr1.reduceRight( (_, obj, i) => {
    if (mp2.has(obj.id)) {
        Object.assign(obj, mp2.get(obj.id)); // update
    } else {
        arr1.splice(i, 1); // delete
    }
}, null);
arr2.forEach( (obj) => {
    if (!mp1.has(obj.id)) {
        arr1.push(obj); // insert
        // If you need the inserted object to be a copy, then do:
        // arr1.push(Object.assign({}, obj));
    }
});

// If you need the result to be sorted by `id`, then do this also:
arr1.sort( (a,b) => a.id - b.id );

console.log(arr1);

Sign up to request clarification or add additional context in comments.

5 Comments

I tried this approach but since this adds everything from array2 to array1 and since I'm using this logic in angular for angular-animate and this animates all the additions instead of just one addition. I only want one addition to have the animation effect and not everything, hence asked this question here, else a simple google search would've solved it. Thanks though
I added a 2nd solution which keeps object references in arr1 in tact when their id exists in arr2.
This looks correct and might work, will test it once I'm home.
this works but if arr1 has 2 objects and arr2 has only 1, then arr1 still results in 2 objects instead of 1 updated from arr2.
Oops, I fixed that now by replacing the forEach with a reduceRight.
1
for(const el of arr2){
 const dupe = arr1.find(e => e.id === el.id);
 if(dupe){
   dupe.quantity = el.quantity;
 }else{
   arr1.push(el);
 }
}

But actually a Map (id -> quantity) would be the better datastructure here (or an object):

const els = new Map( arr1.map(el => [el.id, el.quantity]));
//to add
arr2.forEach( el => els.set( el.id, el.quantity + (els.get( el.id ) ||0));

3 Comments

In the 2nd solution - add a default (els.get( el.id ) || 0) or you'll get a NaN if it's not a duplicate.
nice solution but if the arr2 has lesser elements than arr1 then arr1 doesn't change to arr2.
@ori yeah i always forget about that... :/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.