I've two arrays of objects:
var arr1 = [{
"id": "id_1",
"name": "Skoda"
}, {
"id": "id_2",
"name": "BMW"
}];
var arr2 = [{
"id": "id_1",
"name": "Skoda - Auto"
}, {
"id": "id_3",
"name": "BMW - Auto"
},{
"id": "id_4",
"name": "Merc - Auto"
}]
Output
var arr1 = [{
"id": "id_3",
"name": "BMW - Auto"
},{
"id": "id_4",
"name": "Merc - Auto"
},{
"id": "id_1",
"name": "Skoda"
}, {
"id": "id_2",
"name": "BMW"
}];
I want to merge two arrays arr1 & arr2, basically I want to unshift the object from arr2 to the arr1 only if the Id is not present in arr1, Hence we're not adding id_1
to the arr1. I'm not sure how can we achieve it
I tried the below way but it keeps on adding duplicate items, how can I avoid duplication of id
arr1.unshift.apply(arr1, arr2)
You can reduce all the datasets onto a Map
.
For each item in a dataset, prioritize the first occurrence by assigning it last.
Note: accInner
is technically accOuter
, but they are distinguished as separate variables for the sake of the accumulator argument for each reduce
operation. They are both references to the Map()
initializer.
Also, k
is the value of the id
field (key) of item[key]
. I used an IIFE (Immediately Invoked Function Execution) to avoid creating a block-scope and assigning it as a variable.
// First occurrence of `name` and `a` stays
const arr1 = [
{ "id": "id_1", "name": "Skoda", "a": 1 },
{ "id": "id_2", "name": "BMW" }
];
// Do not override `name` or `a`, but add `b`
const arr2 = [
{ "id": "id_1", "name": "Skoda - Auto", "a": 0, "b": 2 },
{ "id": "id_3", "name": "BMW - Auto" },
{ "id": "id_4", "name": "Merc - Auto" }
];
const mergeByKey = (key, ...dataSets) =>
[...dataSets
.reduce((accOuter, dataSet) =>
dataSet.reduce((accInner, item) =>
((k) =>
accInner.set(k, Object.assign({}, item, accInner.get(k)))) // priority
(item[key]), accOuter), new Map)
.values()]
const arr3 = mergeByKey('id', arr1, arr2); // Priority is left-to-right
console.log(arr3);
.as-console-wrapper { top: 0; max-height: 100% !important; }