Zeyukan Ich'
Zeyukan Ich'

Reputation: 693

Compare two javascript array of objects and merge data

I'm having a bad time comparing two array of objects on a key.

I would like to compare, substract value when the key matches and display negative value when not in my target array. Finally, I want to have all target objects (if key didn't match) inside my final array.

An exemple would save 1000 words :

const initial = [{id: 1, value: 47}, {id: 2, value: 20}, {id: 7, value: 13}];
const target = [{id: 1, value: 150}, {id: 3, value: 70}, {id: 40, value: 477}];
        
//Desired output
// [{id: 1, value: 103}, {id: 2, value: -20}, {id: 7, value: -13}, {id: 3, value: 70}, {id: 40, value: 477}];
        
let comparator = [];
        
initial.map(initia => {
   let hasSame = target.find(targ => {
        return initia.id === targ.id
      });
            
     if(hasSame){
        initia.value -= hasSame.value
     } else{
        initia.value = -initia.value
    }
});

console.log(initial);

I'm getting almost the result I want except that I don't know how to merge target values properly. Is it possible to merge this values without looping over target array once more? Or could I do that inside the find ?

I want to get advice to do this as clean as possible

Thanks you!

Upvotes: 2

Views: 843

Answers (2)

Robert Higdon
Robert Higdon

Reputation: 56

If the intent is to avoid a nested find inside of the loop, you could reduce the two arrays in to a Set. They don't allow duplicate keys, so you would ensure a single value for each ID provided.

const valueSet = [...initial, ...target].reduce((total, obj) => {
  total[obj.id] = !total[obj.id] 
    ? -obj.value
    : total[obj.id] -= obj.value
  return total;
}, {});

const result = Object.keys(valueSet).map(key => ({ id: key, value: valueSet[key]}))
console.log(result);

Then you'd map back over the result to build out the intended array.

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386600

You could use a Map and collect same id with a wanted factor for summing.

As result take key/value as new properties.

var add = (map, factor) => ({ id, value }) => map.set(id, map.has(id)
        ? map.get(id) - value * factor
        : value * factor
    ),
    initial = [ {id: 1, value: 47 }, { id: 2, value: 20 }, { id: 7, value: 13 }],
    target = [{ id: 1, value: 150 }, { id: 3, value: 70 }, { id: 40, value: 477 }],
    map = new Map,
    result;
    
initial.forEach(add(map, -1));
target.forEach(add(map, 1));
result = Array.from(map, ([id, value]) => ({ id, value }));

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

Upvotes: 2

Related Questions