199

Lets have a look at an example.

var arr1 = new Array({name: "lang", value: "English"},
                     {name: "age", value: "18"});

var arr2 = new Array({name : "childs", value: '5'},
                     {name: "lang", value: "German"});

I need to merge those 2 arrays of objects and create the following array:

var arr3 = new Array({name: "lang", value: "German"},
                     {name: "age", value: "18"},
                     {name : "childs", value: '5'});

Is there any JavaScript or jQuery function to do this?

$.extend doesn't suit me. It returns

var arr4 = new Array({name : "childs", value: '5'},
                     {name: "lang", value: "German"});
dreftymac
  • 31,404
  • 26
  • 119
  • 182
Alexander
  • 2,015
  • 2
  • 13
  • 3
  • 29
    What happened to `{name: "lang", value: "English"}`? – Shadow The GPT Wizard Aug 22 '11 at 10:44
  • Sorry. I ment $.extend, not $.merge. – Alexander Aug 22 '11 at 10:49
  • 1
    I mean, what is the logic involved? How you want to merge the arrays? It's not clear from your examples. – Shadow The GPT Wizard Aug 22 '11 at 10:56
  • Thank you all very much. I did it manually. – Alexander Aug 22 '11 at 11:56
  • 13
    @ShadowWizard, I think whats the OP meant was update if exists and push if doesnt. – Amin Mohamed Ajani Sep 27 '16 at 19:22
  • I wonder why this question doesn't have a thousand up votes! – hcarreras Dec 07 '16 at 14:43
  • ... If "lang" and "age" are intended to be keys, then don't need arrays; use properties of objects: `var ob1 = {"lang": "German", "age": "18"};` `var ob2 = {"childs": '5', "lang": "English"};` Then merge for my example (if later "lang" is kept) is: `{"lang": "English", "age": "18", "childs": '5'}`. See [Merge properties of two JS objects](https://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically). – ToolmakerSteve Oct 04 '19 at 08:55
  • 2
    NOTE: This question was fundamentally altered in 2018, when it was edited so that both "lang" entries said "German". Originally, one said "English", the other said "German". This changed the meaning of question from "keep only one element for each 'name'" to "keep elements unless all properties are duplicates". I'm reverting that edit, as some answers would no longer make sense given that edit. This is an example of why one should *avoid significant* edits to questions. Just make grammar and styling changes, that don't change meaning. That opinion should have been a *comment*, not an *edit*. – ToolmakerSteve Oct 04 '19 at 09:24
  • BTW, as shown, this is *not* a traditional merge or join of two arrays. Alexander (OP) is treating the "name" property of each element as if its value were a property key. To do what he wants, requires a custom function, that is told that "name" is special in this way. The top-rated answer *does* show how to do a traditional merge or join of two arrays (but therefore does not do what OP wanted). I don't know whether any other answer does what is asked - because as my first comment says, a better solution is to *not use arrays* for this task. – ToolmakerSteve Oct 04 '19 at 09:36
  • I think this might be a great interview question. A lot of potential for misunderstood requirements, collaborative solution finding and premature optimization – Fozi Sep 30 '20 at 22:28

46 Answers46

124

If you want to merge 2 arrays of objects in JavaScript. You can use this one line trick

Array.prototype.push.apply(arr1,arr2);

For Example

var arr1 = [{name: "lang", value: "English"},{name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];

Array.prototype.push.apply(arr1,arr2); 

console.log(arr1);  // final merged result will be in arr1

Output:

[{"name":"lang","value":"English"},
{"name":"age","value":"18"},
{"name":"childs","value":"5"},
{"name":"lang","value":"German"}]
Jahanzaib Aslam
  • 2,731
  • 3
  • 21
  • 26
  • DOESNT WORK for updating values. Proof here: https://jsfiddle.net/aminajani17/s76x6hh4/ – Amin Mohamed Ajani Sep 28 '16 at 00:04
  • @AminMohamedAjani Ah! got your point. Yes you are right. but if you just want to merge two arrays then you can use above mentioned one line simple solution. – Jahanzaib Aslam Oct 03 '16 at 11:18
  • As question title says "Merge 2 arrays of objects". Simply use 'Array.prototype.push.apply(arr1,arr2); ' If you want to merge 2 arrays of objects in JavaScript. – Jahanzaib Aslam Oct 03 '16 at 11:26
  • 31
    same result as the much simpler: `arr1 = arr1.concat(arr2)` – keithpjolley Nov 01 '16 at 14:55
  • @keithpjolley you can not get above output using 'concat' if you have two merge array of objects. Please check this out https://jsfiddle.net/jahanzaibaslam/z22n5tuo/ – Jahanzaib Aslam Feb 16 '17 at 18:39
  • Array.prototype.push.apply(arr1,arr2); or arr1 = arr1.concat(arr2) both are working. Thax.., – gnganapath Jul 14 '17 at 18:19
  • 27
    but this is not merge! – Dimitri Kopriwa Dec 06 '17 at 16:34
  • 4
    The results are not the same. `concat` will return a new array and break any references you had. – Bpainter Jul 09 '18 at 17:52
  • As @JahanzaibAslam showed in jsfiddle.net/jahanzaibaslam/z22n5tuo, concat doesn't work if you need to merge array of **objects**. In his example, make var arr1 = []; - result will be even more obvious (empty). – vkelman Jun 18 '19 at 19:27
  • 38
    This doesn't answer the question, the resulting array should have 3 objects, not 4. You changed the sample values. Basically what OP wants is to merge two object arrays and remove duplicate values. – Ranjan Sep 18 '19 at 06:17
70

With ES6 you can do it very easy as below:

var arr1 = new Array({name: "lang", value: "German"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var arr3 = [...arr1, ...arr2];

Output:

    arr3 = [
      {"name":"lang","value":"German"},
      {"name":"age","value":"18"},
      {"name":"childs","value":"5"},
      {"name":"lang","value":"German"}
    ]
55

For those who are experimenting with modern things:

var odd = [{
    name: "1",
    arr: "in odd"
  },
  {
    name: "3",
    arr: "in odd"
  }
];

var even = [{
    name: "1",
    arr: "in even"
  },
  {
    name: "2",
    arr: "in even"
  },
  {
    name: "4",
    arr: "in even"
  }
];

// ----
// ES5 using Array.filter and Array.find
function merge(a, b, prop) {
  var reduced = a.filter(function(aitem) {
    return !b.find(function(bitem) {
      return aitem[prop] === bitem[prop];
    });
  });
  return reduced.concat(b);
}
console.log("ES5", merge(odd, even, "name"));

// ----
// ES6 arrow functions
function merge(a, b, prop) {
  var reduced = a.filter(aitem => !b.find(bitem => aitem[prop] === bitem[prop]))
  return reduced.concat(b);
}
console.log("ES6", merge(odd, even, "name"));

// ----
// ES6 one-liner
var merge = (a, b, p) => a.filter(aa => !b.find(bb => aa[p] === bb[p])).concat(b);


console.log("ES6 one-liner", merge(odd, even, "name"));

// Results
// ( stuff in the "b" array replaces things in the "a" array )
// [
//    {
//         "name": "3",
//         "arr": "in odd"
//     },
//     {
//         "name": "1",
//         "arr": "in even"
//     },
//     {
//         "name": "2",
//         "arr": "in even"
//     },
//     {
//         "name": "4",
//         "arr": "in even"
//     }
// ]


// for posterity, here's the old skool version

function merge(a, b, prop) {
  var reduced = [];
  for (var i = 0; i < a.length; i++) {
    var aitem = a[i];
    var found = false;
    for (var ii = 0; ii < b.length; ii++) {
      if (aitem[prop] === b[ii][prop]) {
        found = true;
        break;
      }
    }
    if (!found) {
      reduced.push(aitem);
    }
  }
  return reduced.concat(b);
}
bob
  • 7,539
  • 2
  • 46
  • 42
  • 1
    maybe this should be called "mergeOn"? – bob Aug 19 '21 at 16:49
  • 1
    I liked your solution. ArrA will overwrite objects in ArrB. Non-intersecting objects will be concatinated to the resulting array `const mergeArrayAtoB = (arrA, arrB, property) => arrB.filter(b => !arrA.find(a => b[property] === a[property])).concat(arrA);` – xeiton Nov 04 '21 at 21:15
  • 1
    man you're a life saver. Thank you – jpisty Dec 08 '21 at 01:16
53

Update 12 Oct 2019

New version based only on newer Javascript and without the need of any 3rd party library.

const mergeByProperty = (target, source, prop) => {
  source.forEach(sourceElement => {
    let targetElement = target.find(targetElement => {
      return sourceElement[prop] === targetElement[prop];
    })
    targetElement ? Object.assign(targetElement, sourceElement) : target.push(sourceElement);
  })
}
var target /* arr1 */ = [{name: "lang", value: "English"}, {name: "age", value: "18"}];
var source /* arr2 */ = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];

mergeByProperty(target, source, 'name');

console.log(target)

This answer was getting old, libs like lodash and underscore are much less needed these days. In this new version, the target (arr1) array is the one we’re working with and want to keep up to date. The source (arr2) array is where the new data is coming from, and we want it merged into our target array.

We loop over the source array looking for new data, and for every object that is not yet found in our target array we simply add that object using target.push(sourceElement) If, based on our key property ('name'), an object is already in our target array - we update its properties and values using Object.assign(targetElement, sourceElement). Our “target” will always be the same array and with updated content.


Old answer using underscore or lodash

I always arrive here from google and I'm always not satisfy from the answers. YOU answer is good but it'll be easier and neater using underscore.js

DEMO: http://jsfiddle.net/guya/eAWKR/

Here is a more general function that will merge 2 arrays using a property of their objects. In this case the property is 'name'

var arr1 = [{name: "lang", value: "English"}, {name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];

function mergeByProperty(arr1, arr2, prop) {
  _.each(arr2, function(arr2obj) {
    var arr1obj = _.find(arr1, function(arr1obj) {
      return arr1obj[prop] === arr2obj[prop];
    });

    arr1obj ? _.extend(arr1obj, arr2obj) : arr1.push(arr2obj);
  });
}

mergeByProperty(arr1, arr2, 'name');

console.log(arr1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.core.min.js"></script>
[{name: "lang", value: "German"}, {name: "age", value: "18"}, {name : "childs", value: '5'}]
Community
  • 1
  • 1
guya
  • 5,067
  • 1
  • 35
  • 28
  • 6
    Almost identical in LOC, complexity as @YOU's answer, except that this is much slower (largely due to extra function calls and the fact the YOU's answer exploits the JS associative arrays trick to find items with O(1) lookup). This is besides the fact that you need to bring an additional library. – Mrchief Jan 21 '15 at 20:59
  • You wouldn't get any difference in performance unless you're dealing with extreme edge cases. Regarding the extra lib - underscore, lodash and alike are generally already used and have other benefits, one should consider using it anyway. Most developers and apps will benefit from the simplicity and generality of this solution. – guya Jun 04 '15 at 19:47
  • 1
    @guya I realise this is old but **underscore, lodash and alike are generally already used and have other benefits** while as you say they have other benefits, its a huge assumption to say they are generally already used. – Craicerjack Feb 02 '17 at 12:43
  • 1
    The new version works in Nodejs. Thanks, May God bless you!! – Aniket Malik Jan 23 '21 at 05:08
43

Very simple using ES6 spread operator:

const array1 = [{a: 'HI!'}, {b: 'HOW'}]
const array2 = [{c: 'ARE'}, {d: 'YOU?'}]

const mergedArray = [ ...array1, ...array2 ]
console.log('Merged Array: ', mergedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Merged Array: [ {a: 'HI!'}, {b: 'HOW'} {c: 'ARE'}, {d: 'YOU?'} ]

Note: The above solution is to just merge two arrays using ES6 spread operator.

Edit on 07 January 2020 by @bh4r4th : As the context changed due to edits after my initial solution. I would like to update my solution to match current criteria. i.e.,

  1. Merger array objects without creating duplicate objects and,

  2. update the value if the name property already exists in the prior array

const arr1 = [
    { name: "lang", value: "English" },
    { name: "age", value: "18" }
]
const arr2 = [
    { name: "childs", value: '2' }, 
    { name: "lang", value: "German" }
]
const arr3 = [
    { name: "lang", value: "German" },
    { name: "age", value: "28" },
    { name: "childs", value: '5' }
]

// Convert to key value dictionary or object
const convertToKeyValueDict = arrayObj => {
    const val = {}
    arrayObj.forEach(ob => {
        val[ob.name] = ob.value
    })
    return val
}

// update or merge array
const updateOrMerge = (a1, a2) => {
    const ob1 = convertToKeyValueDict(a1)
    const ob2 = convertToKeyValueDict(a2)
    // Note: Spread operator with objects used here
    const merged_obj = {...ob1, ...ob2}
    const val = Object.entries(merged_obj)
    return val.map(obj => ({ name: obj[0], value: obj[1] }))
}

const v1 = updateOrMerge(arr1, arr2)
const v2 = updateOrMerge(v1, arr3)
console.log(`Merged array1 and array2: ${JSON.stringify(v1)} \n\n`)
console.log(`Merged above response and array3: ${JSON.stringify(v2)} \n\n`)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
bh4r4th
  • 3,760
  • 1
  • 21
  • 25
  • 2
    This should be the accepted answer in 2019! I was going to propose the same solution after looking at the other answers with higher vote count! @Alexander It's easy to miss but please accept this one! – iaforek Jul 04 '19 at 08:38
  • 2
    Incorrect. The questioner specifically wants to REPLACE objects if they have a duplicate property, not simply append them. – HaveSpacesuit Jan 06 '20 at 16:32
  • Thanks for pointing that @HaveSpacesuit . I have answered this question in 2018 when the context is to just merge two arrays. Will edit this answer soon to use `set` upon merge to remove duplicates. This would create new variable argument but minimal code. However, I am not a big fan of payload which has names defined as properties and values as different types. Instead I prefer ```[ { lang: 'German', age: 25}] ```. This way payload weight will be minimised while communicating between services. – bh4r4th Jan 06 '20 at 22:06
  • I have now updated the solution to match the changed context of the question. – bh4r4th Jan 07 '20 at 06:45
  • worked perfect! this answer deserves more attention – Barlas Apaydin Apr 29 '22 at 11:43
27
var arr3 = [];
for(var i in arr1){
   var shared = false;
   for (var j in arr2)
       if (arr2[j].name == arr1[i].name) {
           shared = true;
           break;
       }
   if(!shared) arr3.push(arr1[i])
}
arr3 = arr3.concat(arr2);

enter image description here

YOU
  • 120,166
  • 34
  • 186
  • 219
20

Merging two arrays:

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var result=arr1.concat(arr2);
// result: [{name: "lang", value: "English"}, {name: "age", value: "18"}, {name : "childs", value: '5'}, {name: "lang", value: "German"}]

Merging two arrays without duplicated values for 'name':

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var i,p,obj={},result=[];
for(i=0;i<arr1.length;i++)obj[arr1[i].name]=arr1[i].value;
for(i=0;i<arr2.length;i++)obj[arr2[i].name]=arr2[i].value;
for(p in obj)if(obj.hasOwnProperty(p))result.push({name:p,value:obj[p]});
// result: [{name: "lang", value: "German"}, {name: "age", value: "18"}, {name : "childs", value: '5'}]
Andrew D.
  • 8,130
  • 3
  • 21
  • 23
  • 1
    Array.concat is the proper way to merge 2 arrays into one. I also like the extended assumption that the concept of "true" merge was addressed (based on a given key of each array element) . – bob Jan 29 '17 at 08:31
14

The easiest way is with some ES6 magic:

Merge two with duplicates:

const a = [{a: 1}, {b: 2}]
const b = [{a: 1}]

const result = a.concat(b) // [{a: 1}, {b: 2}, {a: 1}]

Without duplicates it is same as the above plus:

const distinct = [...new Set(result.map(item => item.YOUR_PROP_HERE))]

knikolov
  • 1,650
  • 1
  • 12
  • 18
14

I'd merge two arrays with duplicates and then use my this answer to remove duplicates. This looks like shortest way.

const arr1 = [{
    name: "lang",
    value: "English"
  },
  {
    name: "age",
    value: "18"
  }
];

const arr2 = [{
    name: "childs",
    value: '5'
  },
  {
    name: "lang",
    value: "German"
  }
];

const mergedArray = [...arr1, ...arr2];
const uniqueData = [...mergedArray.reduce((map, obj) => map.set(obj.name, obj), new Map()).values()];

console.log(uniqueData)
doğukan
  • 23,073
  • 13
  • 57
  • 69
11

With lodash:

_.uniqBy([...arr1, ...arr2], 'name')
Pietro
  • 1,815
  • 2
  • 29
  • 63
7

Yet another version using reduce() method:

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});

var arr = arr1.concat(arr2).reduce(function(prev, current, index, array){ 
   
   if(!(current.name in prev.keys)) {
      prev.keys[current.name] = index;
      prev.result.push(current);   
   } 
   else{
       prev.result[prev.keys[current.name]] = current;
   }  

   return prev;
},{result: [], keys: {}}).result;
  
document.getElementById("output").innerHTML = JSON.stringify(arr,null,2);    
<pre id="output"/>
Vadim Gremyachev
  • 57,952
  • 20
  • 129
  • 193
  • This worked great for me. One small issue though is the ordering sometimes is odd when merging 3 large json objects – crh225 Sep 01 '16 at 13:42
7

This is how I've tackled a similar issue in an ES6 context:

function merge(array1, array2, prop) {
    return array2.map(function (item2) {
        var item1 = array1.find(function (item1) {
            return item1[prop] === item2[prop];
        });
        return Object.assign({}, item1, item2);
    });
}

Note: This approach will not return any items from array1 that don't appear in array2.


EDIT: I have some scenarios where I want to preserve items that don't appear in the second array so I came up with another method.

function mergeArrays(arrays, prop) {
    const merged = {};

    arrays.forEach(arr => {
        arr.forEach(item => {
            merged[item[prop]] = Object.assign({}, merged[item[prop]], item);
        });
    });

    return Object.values(merged);
}

var arr1 = [
    { name: 'Bob', age: 11 },
    { name: 'Ben', age: 12 },
    { name: 'Bill', age: 13 },
];

var arr2 = [
    { name: 'Bob', age: 22 },
    { name: 'Fred', age: 24 },
    { name: 'Jack', age: 25 },
    { name: 'Ben' },
];

console.log(mergeArrays([arr1, arr2], 'name'));
marktuk
  • 95
  • 2
  • 7
6

jsut using vanilla js (ES6 version)

// no need new Array constructor, just using an array literal
const arr1 = [{name: "lang", value: "English"}, {name: "age", value: "18"}];
const arr2 = [{name: "childs", value: '5'}, {name: "lang", value: "German"}];

// 1. create a map
const map = new Map();

// 2. concat array
// arr1.concat(arr2) === [...arr1, ...arr2]
const arr3 = [...arr1, ...arr2];

// 3. for ... of, iterator array
for(const obj of arr3) {
  if(!map.has(obj.name)) {
    // add
    map.set(obj.name, obj);
  } else {
    // update
    map.set(obj.name, {
      ...map.get(obj.name),
      ...obj,
    });
  }
}

// 4. get new merged unqiue array
const arr4 = [...map.values()];

console.log(`result array =`, JSON.stringify(arr4, null, 4));

/*

result array = [
    {
        "name": "lang",
        "value": "German"
    },
    {
        "name": "age",
        "value": "18"
    },
    {
        "name": "childs",
        "value": "5"
    }
]

*/

test ✅ (Chrome)

enter image description here

refs

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#array_literals

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
  • I found this to be the most useful in my scenario. I had objects that could share several key values that needed to be joined. I used maps in the same way, but first created maps for each original array. They key for each was a combined string of all items that needed to be the same for them to be considered the same object. They only got combined if all were the same. Thanks – jake Sep 21 '21 at 11:51
5

Simple solution

var tx = [{"id":1},{"id":2}];
var tx1 = [{"id":3},{"id":4}];


var txHistory = tx.concat(tx1)

console.log(txHistory); 
// output
 // [{"id":1},{"id":2},{"id":3},{"id":4}];
Shashwat Gupta
  • 5,071
  • 41
  • 33
4

Solution utilizing JS Map:

const merge = (arr1, arr2, prop) => {
    const resultMap = new Map(arr1.map((item) => [item[prop], item]));
    arr2.forEach((item) => {
        const mapItem = resultMap.get(item[prop]);
        if (mapItem) Object.assign(mapItem, item);
        else resultMap.set(item[prop], item);
    });
    return [...resultMap.values()];
};

const arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
const arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});

console.log(merge(arr1, arr2, "name"));

Which produces:

merge() function outcome

2DH
  • 1,648
  • 2
  • 10
  • 19
4

You could use an object to collect up your properties while replacing duplicates and then expand/flatten that object back to an array. Something like this:

function merge(args) {
    args  = Array.prototype.slice.call(arguments);
    var o = { };
    for(var i = 0; i < args.length; ++i)
        for(var j = 0; j < args[i].length; ++j)
            o[args[i][j].name] = args[i][j].value;
    return o;
}

function expand(o) {
    var a = [ ];
    for(var p in o)
        if(o.hasOwnProperty(p))
            a.push({ name: p, value: o[p]});
    return a;
}

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var arr3 = expand(merge(arr1, arr2));

I don't know if this is the fastest way but it works for any number of input arrays; for example, this:

var a = expand(
    merge(
        [{name: "lang", value: "English"}, {name: "age", value: "18"}],
        [{name: "childs", value: '5'}, {name: "lang", value: "German"}],
        [{name: 'lang', value: 'Pancakes'}]
    )
);

Gives you the same thing in a that was in arr3 with "German" replaced by "Pancakes".

This approach does assume that your objects all have the same {name: ..., value: ...} form of course.

You can see it working here (open your console please): http://jsfiddle.net/ambiguous/UtBbB/

mu is too short
  • 426,620
  • 70
  • 833
  • 800
3

you could use following function

const merge = (a, b, key = "id") =>
  a.filter(elem => !b.find(subElem => subElem[key] === elem[key]))
   .concat(b);

and try

merge(arr1, arr2, 'name');
Diogo Alves
  • 101
  • 4
  • Thanks to Diago way with ES6 immutable feature ``` export const mergeArrays = (a1, a2, key="id") => a1 && a2 != null ? [...a1.filter(a => !a2.find(p => p[key] === a[key])), ...a2] : null; ``` – Musa Sep 05 '18 at 14:36
2

I was facing the same problem and based on guya answer I have extended the underscore library and also added a bit more of functionality that I was requiring. Here's the Gist.

/**
 * Merges two object-like arrays based on a key property and also merges its array-like attributes specified in objectPropertiesToMerge.
 * It also removes falsy values after merging object properties.
 *
 * @param firstArray The original object-like array.
 * @param secondArray An object-like array to add to the firstArray.
 * @param keyProperty The object property that will be used to check if objects from different arrays are the same or not.
 * @param objectPropertiesToMerge The list of object properties that you want to merge. It all must be arrays.
 * @returns The updated original array.
 */
function merge(firstArray, secondArray, keyProperty, objectPropertiesToMerge) {

    function mergeObjectProperties(object, otherObject, objectPropertiesToMerge) {
        _.each(objectPropertiesToMerge, function (eachProperty) {
            object[eachProperty] = _.chain(object[eachProperty]).union(otherObject[eachProperty]).compact().value();
        });
    }

    if (firstArray.length === 0) {
        _.each(secondArray, function (each) {
            firstArray.push(each);
        });
    } else {
        _.each(secondArray, function (itemFromSecond) {
            var itemFromFirst = _.find(firstArray, function (item) {
                return item[keyProperty] === itemFromSecond[keyProperty];
            });

            if (itemFromFirst) {
                mergeObjectProperties(itemFromFirst, itemFromSecond, objectPropertiesToMerge);
            } else {
                firstArray.push(itemFromSecond);
            }
    });
    }

    return firstArray;
}

_.mixin({
            merge: merge
        });

Hope it to be useful! Regards!

Community
  • 1
  • 1
Nahuel Barrios
  • 1,870
  • 19
  • 22
2

I was recently stumped with this problem and I came here with the hope to have an answer but the accepted answer uses 2 for in loops which I wouldn't prefer. I finally managed to make my own. Doesn't depend on any library whatsoever:

function find(objArr, keyToFind){
    var foundPos = objArr.map(function(ob){
        return ob.type;
    }).indexOf(keyToFind);
    return foundPos;
}

function update(arr1,arr2){
    for(var i = 0, len = arr2.length, current; i< len; i++){
        var pos = find(arr1, arr2[i].name); 
        current = arr2[i];
        if(pos !== -1) for(var key in arr2) arr1[pos][key] = arr2[key];
        else arr1[arr1.length] = current;
    } 
}

This also maintains the order of arr1.

2

var arr1 = [{ name: "lang", value: "English" }, { name: "age", value: "18" }];
var arr2 = [{ name: "childs", value: '5' }, { name: "lang", value: "German" }];

function mergeArrayByProperty(arr1, arr2, prop) {
    var newArray =
        arr1.map(item => {
            if (typeof (item[prop]) !== "undefined") {
                var nItems = arr2.filter(ni => { if (typeof (ni[prop]) !== "undefined" && ni[prop] === item[prop]) return ni; });
                if (nItems.length > 0) {
                    item = Object.assign({}, item, nItems[0]);
                }
                return item;
            }
        });
    var arr2nd = arr2.flatMap(item => { return item[prop] });
    var arr1nd = arr1.flatMap(item => { return item[prop] });
    var nonDupArr = arr2nd.map(p => { if (arr1nd.includes(p) === false) return arr2.filter(i2 => { if (i2[prop] === p) return Object.assign({}, i2) })[0]; });
    return newArray.concat(nonDupArr).filter(i=>{if(i !== null)return i})
}
var arr = mergeArrayByProperty(arr1, arr2, 'name');
console.log(arr)
I know this has been answered a lot, but I thought I would share.

This finds the duplicate key in the first array and merges the second arrays object having the same key value. If no value is found in the second array, it uses the original object. As you can see, lang is only found once in the result set; having german for the value.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Jay Stratemeyer
  • 506
  • 4
  • 6
2

What about jQuery Merge?

http://api.jquery.com/jQuery.merge/

jsFiddle example here: http://jsfiddle.net/ygByD/

321X
  • 3,153
  • 2
  • 30
  • 42
2
  1. Using the traditional for loop

const merge = (first, second) => {
  for(let i=0; i<second.length; i++) {
    first.push(second[i]);
  }
  return first;
}

console.log(merge([1,2,3], [4,5,6])); // [1,2,3,4,5,6]
console.log(merge(merge([1,2,3], [4,5,6]), [7,8,9])); // [1,2,3,4,5,6,7,8,9]
  1. Using the Spread operator

const arr1 = [1,2,3];
const arr2 = [4,5,6];

// Merge arrays
const merged = [...arr1, ...arr2];

console.log(merged); // [1,2,3,4,5,6]
  1. Using the concat() array method

const arr1 = [1,2,3];
const arr2 = [4,5,6];

// Merge arrays
const merged1 = arr1.concat(arr2); // bit confusing, seems like `arr1` itself is being modified but it's not
const merged2 = [].concat(arr1, arr2); // cleaner approach

console.log(merged1); // [1,2,3,4,5,6]
console.log(merged2); // [1,2,3,4,5,6]
  1. Using the push() array method

const arr1A = [1,2,3];
const arr2A = [4,5,6];

const arr1B = [1,2,3];
const arr2B = [4,5,6];

const arr1C = [1,2,3];
const arr2C = [4,5,6];
const arr3C = [7,8,9];

// Merge arrays
const merged1 = arr1A.push(...arr2A);

// Merging without the ... on arr2B
const merged2 = arr1B.push(arr2B);

// Merge more than two arrays
arr1C.push(...[...arr2C, ...arr3C]);
console.log(arr1C); // [1,2,3,4,5,6,7,8,9]

console.log(merged1); // 6
console.log(arr1A); // [1,2,3,4,5,6]
console.log(arr2A); // [4,5,6]

console.log(merged2); // 4
console.log(arr1B); // [1,2,3,[4,5,6]]
console.log(arr2B); // [4,5,6]
  1. Using the reduce() array method

const arr1 = [1,2,3];
const arr2 = [4,5,6];

const merged = arr2.reduce((arr, item) => {
    arr.push(item);
    return arr;    
}, arr1);

console.log(merged); // [1,2,3,4,5,6]

To Summarize,

  • There are more than a couple of ways to merge two or more arrays into one in JavaScript.
  • Using the spread operator or the concat() method is the most optimal solution.
  • If you are sure that all inputs to merge are arrays, use spread operator. In case you are unsure, use the concat() method.
  • You can use the push() method to merge arrays when you want to change one of the input arrays to merge.
  • Using the reduce() method to merge arrays is a bit of overhead.

For more info refer the detailed blog here and video here

Syed
  • 15,657
  • 13
  • 120
  • 154
1

var newArray = yourArray.concat(otherArray); console.log('Concatenated newArray: ', newArray);

  • i agree that this makes much more sense than the `Array.protype.push.apply()` answer, but, it doesn't do the merge like OP wanted. – keithpjolley Nov 01 '16 at 14:54
  • you can not get above output using 'concat' if you have two merge array of objects. Please check this out https://jsfiddle.net/jahanzaibaslam/z22n5tuo/ – Jahanzaib Aslam Feb 16 '17 at 18:40
1

Here I first filter arr1 based on element present in arr2 or not. If it's present then don't add it to resulting array otherwise do add. And then I append arr2 to the result.

arr1.filter(item => {
  if (!arr2.some(item1=>item.name==item1.name)) {
    return item
  }
}).concat(arr2)
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • Kindly provide the explanation to your answer. So if any other person read the question and answer then it can easily understood. – Mittal Patel Jul 06 '18 at 18:25
  • While this answer is probably correct and useful, it is preferred if you include some explanation along with it to explain how it helps to solve the problem. This becomes especially useful in the future, if there is a change (possibly unrelated) that causes it to stop working and users need to understand how it once worked. – Erty Seidohl Jul 06 '18 at 19:04
  • Thank you guys. I updated the solution description. If it seems correct pls upvote :) – maulik bhatt Jul 06 '18 at 22:16
1
let mergeArray = arrA.filter(aItem => !arrB.find(bItem => aItem.name === bItem.name))
Tim2.0
  • 109
  • 1
  • 2
1

Posting this because unlike the previous answers this one is generic, no external libraries, O(n), actually filters out the duplicate and keeps the order the OP is asking for (by placing the last matching element in place of first appearance):

function unique(array, keyfunc) {
    return array.reduce((result, entry) => {
        const key = keyfunc(entry)
        if(key in result.seen) {
            result.array[result.seen[key]] = entry
        } else {
            result.seen[key] = result.array.length
            result.array.push(entry)
        }
        return result
    }, { array: [], seen: {}}).array
}

Usage:

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"})
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"})

var arr3 = unique([...arr1, ...arr2], x => x.name)
/* arr3 == [ 
    {name: "lang", value: "German"}, 
    {name: "age", value: "18"},
    {name: "childs", value: "5"}
]*/
Fozi
  • 4,973
  • 1
  • 32
  • 56
1
const arr1 = [{ name: "lang", value: "English" }, { name: "age", value: "18" }];
const arr2 = [{ name: "childs", value: '5' }, { name: "lang", value: "German" }];

const mergeArrOfObjects = (dataset1, dataset2) => {
    const map1 = new Map();
    dataset1.map((d1, i) => {
        map1.set(d1.name, i);
    })
    for (let d2 of dataset2) {
        if (d2 && map1.has(d2.name)) {
            dataset1[map1.get(d2.name)] = d2;
        } else if(d2){
            dataset1.push(d2);
        }
    }
    return dataset1;
};

const arr3 = mergeArrOfObjects(arr1, arr2);
console.log(arr3);
Pavneet Kaur
  • 729
  • 7
  • 5
1

Just use helprjs

const arr1 = [{ id: 1, name: 'Jack'}, { id: 2, name: 'Jack'}];
const arr2 = [{ id: 2, name: 'Jane'}, { id: 3, name: 'Rod'}];

mergeArrays(arr1, arr2, "name");
// [{ id: 1, name: 'Jack'}, { id: 2, name: 'Jane'}, { id: 3, name: 'Rod'}];

mergeArrays(arr1, arr2, "id");
// [{ id: 1, name: 'Jack'}, { id: 2, name: 'Jack'}, { id: 3, name: 'Rod'}];

Check out the demo

1

Based on the question, I understand that there is a key that you want to use to override other attributes, not to merge them.

interface Foo {
    name: string;
    value: string;
}

var arr1: Foo[] = [
    { name: "lang", value: "English" },
    { name: "age", value: "18" },
];

var arr2: Foo[] = [
    { name: "childs", value: "5" },
    { name: "lang", value: "German" },
];

We can use combination of Map with Reduce to select the key that will be used to overwrite the record.

const merged: Foo[] = Array.from(
  [...arr1, ...arr2].reduce(
      (acc, curr) => acc.set(curr.name, curr),
      new Map<Foo["name"], Foo>(),
    )
    .values(),
);

// [
//   { name: "lang", value: "German" },
//   { name: "age", value: "18" },
//   { name: "childs", value: "5" },
// ];
Filip Seman
  • 1,252
  • 2
  • 15
  • 22
1

Off the top of my head - try jquery extend

var arr3 = jQuery.extend(arr1,arr2....)
Xhalent
  • 3,914
  • 22
  • 21
  • Sorry. Exactly this function returns arr4. Not $.merge. The last one doesn't suit me too, because it duplicates objects. – Alexander Aug 22 '11 at 10:48
0

Based on @YOU's answer but keeping the order:

var arr3 = [];
for(var i in arr1){
   var shared = false;
   for (var j in arr2)
       if (arr2[j].name == arr1[i].name) {
           arr3.push(arr1[j]
           shared = true;
           break;
       }
   if(!shared) arr3.push(arr1[i])
}

for(var j in arr2){
   var shared = false;
   for (var i in arr1)
       if (arr2[j].name == arr1[i].name) {
           shared = true;
           break;
       }
   if(!shared) arr3.push(arr2[j])
}
arr3

I know this solution is less efficient, but it's necessary if you want to keep the order and still update the objects.

hcarreras
  • 4,442
  • 2
  • 23
  • 32
0

Here's a jQuery plugin that I wrote to merge two object arrays by a key. Keep in mind that this modifies the destination array in-place.

(function($) {
  $.extendObjectArray = function(destArray, srcArray, key) {
    for (var index = 0; index < srcArray.length; index++) {
      var srcObject = srcArray[index];
      var existObject = destArray.filter(function(destObj) {
        return destObj[key] === srcObject[key];
      });
      if (existObject.length > 0) {
        var existingIndex = destArray.indexOf(existObject[0]);
        $.extend(true, destArray[existingIndex], srcObject);
      } else {
        destArray.push(srcObject);
      }
    }
    return destArray;
  };
})(jQuery);

var arr1 = [
  { name: "lang",   value: "English" },
  { name: "age",    value: "18"      }
];
var arr2 = [
  { name: "childs", value: '5'       },
  { name: "lang",   value: "German"  }
];
var arr3 = $.extendObjectArray(arr1, arr2, 'name');

console.log(JSON.stringify(arr3, null, 2));
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

ES6 Version

(function($) {
  $.extendObjectArray = (destArr, srcArr, key) => {
    srcArr.forEach(srcObj => (existObj => {
      if (existObj.length) {
        $.extend(true, destArr[destArr.indexOf(existObj[0])], srcObj);
      } else {
        destArr.push(srcObj);
      }
    })(destArr.filter(v => v[key] === srcObj[key])));
    return destArr;
  };
})(jQuery);
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

Using lodash you want _.uniqBy

var arr3 = _.uniqBy(arr1.concat(arr2), 'name'); // es5

let arr3 = _.uniqBy([...arr1, ...arr2], 'name'); // es6

Order of arr1, arr2 matters!

See docs https://lodash.com/docs/4.17.4#uniqBy

danday74
  • 52,471
  • 49
  • 232
  • 283
0
const extend = function*(ls,xs){
   yield* ls;
   yield* xs;
}

console.log( [...extend([1,2,3],[4,5,6])]  );
codemonkey
  • 21
  • 4
0
merge(a, b, key) {
    let merged = [];
    a.forEach(aitem => {
        let found = b.find( bitem => aitem[key] === bitem[key]);
        merged.push(found? found: aitem);
    });
    return merged;
}
Kyaw
  • 61
  • 1
  • 2
0

If you want to merge the 2 arrays, but remove duplicate objects use this. Duplicates are identified on .uniqueId of each object

function mergeObjectArraysRemovingDuplicates(firstObjectArray, secondObjectArray) {
  return firstObjectArray.concat(
    secondObjectArray.filter((object) => !firstObjectArray.map((x) => x.uniqueId).includes(object.uniqueId)),
  );
}
daveanderson88
  • 327
  • 1
  • 4
  • 12
0

Try this:

var a = [{"a":20, "b":10,"c":"c","d":"asd","f":"any"}]
var b = [{"a":20, "b":10,"c":"c", "e":"nan","g":10200}]

var p = []
_.map(a, function(da){
var chk = _.filter(b, function(ds){
return da.a ===ds.a
})[0]
p.push(_.extend(da, chk))


})

console.log(p)

OutPut will be :

  [{
    "a": 20,
    "b": 10,
    "c": "c",
    "d": "asd",
    "f": "any",
    "e": "nan",
    "g": 10200
  }]
Rohit Parte
  • 3,365
  • 26
  • 26
0
const arr1 = ["Vijendra","Singh"];
const arr2 = ["Singh", "Shakya"];

arr2.forEach(item => {
        if(!arr1.find(k => k===item))
          arr1.push(item)
    });


console.log(arr1)
Nico Griffioen
  • 5,143
  • 2
  • 27
  • 36
Gajju
  • 31
  • 1
  • 5
0
const array1 = [{id:1,name:'ganza'},
{id:2,name:'respice dddd'},{id:4,name:'respice dddd'},{id:6,name:'respice dddd'},
{id:7,name:'respice dddd'}];
const array2 = [{id:1,name:'ganza respice'},{id:2,name:'respice'},{id:3,name:'mg'}];

 function mergeTwoArray(array1,array2){

    return array1.map((item,i)=>{
        if(array2[i] && item.id===array2[i].id){
          return array2[i];
          }else{
            return item;
          }
    });
  }

const result = merge(array1,array2);
console.log(result);
//here is the result:  Array [Object { id: 1, name: "ganza respice" }, Object { id: 2, name: "respice" }, Object { id: 4, name: "respice dddd" }, Object { id: 6, name: "respice dddd" }, Object { id: 7, name: "respice dddd" }]
Ganza respice
  • 31
  • 1
  • 2
0
const array1 = [{id:1,name:'ganza'},
{id:2,name:'respice dddd'},{id:4,name:'respice dddd'},{id:6,name:'respice dddd'},
{id:7,name:'respice dddd'}];
const array2 = [{id:1,name:'ganza respice'},{id:2,name:'respice'},{id:3,name:'mg'}];

 function mergeTwoArray(array1,array2){

    return array1.map((item,i)=>{
        if(array2[i] && item.id===array2[i].id){
          return array2[i];
          }else{
            return item;
          }
    });
  }

const result = mergeTwoArray(array1,array2);
console.log(result);
//here is the result:  Array [Object { id: 1, name: "ganza respice" },
 Object { id: 2, name: "respice" }, Object { id: 4, name: "respice dddd" }, 
Object { id: 6, name: "respice dddd" }, Object { id: 7, name: "respice dddd" }]

Ganza respice
  • 31
  • 1
  • 2
  • While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Piotr Labunski Mar 13 '20 at 09:42
0

You can leverage hash maps and Object.values to accomplish this in roughly O(3n) time. This looks like O(n^2), but the outer loop is just to iterate through the arrays to be merged.

function uniqueMerge(arrays) {
  const results = {};
  arrays.forEach((arr) => {
    arr.forEach(item => {
      results[item.name] = item;
    });
  });

  return Object.values(results);
}

enter image description here

unforgiven1987
  • 454
  • 1
  • 3
  • 18
0

Highest voted responses did not meet the requirements, @Diogo Alves and @Pietro's answer is right, but you need to be careful with the order.

enter image description here

enter image description here

ZiShi
  • 101
  • 5
0

If you want to merge 2 arrays of objects in JavaScript, you can use for...of like this:

var arr1 = [{name: "lang", value: "English"},{name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];

for (const x of arr2){ arr1.push(x); }

console.log(arr1);
Vasilis Plavos
  • 230
  • 2
  • 8
0

// simply like this

var arr1 = [{name: "lang", value: "English"},{name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];
                         
                
const obj1 = arr2[1];
const obj2 = arr1[1];
const obj3 = arr2[0];
const result = [obj1, obj2, obj3];
// or 

let arr = [...arr2];
for (let x = 0; x < arr2.length; x++) {
  arr1.sort((a, b) => a.name.localeCompare(b.name));
  arr2.sort((a, b) => a.name.localeCompare(b.name));
  if (arr2[x].name !== arr1[x].name) {
    arr.push(arr1[x]);
  }
}
 
Rio0o.dev
  • 25
  • 6
  • It's important to not just post code, but to also include a description of what the code does and why you are suggesting it. This helps others understand the context and purpose of the code, and makes it more useful for others who may be reading the question or answer. @Rio0o.dev . – DSDmark Dec 29 '22 at 17:36
0
var arr1 = [{name: "lang", value: "English"},{name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];


function merge_by_property(arr1, arr2, prop) {
  return arr2.reduce((accumulator, current) => {
    const index = accumulator.findIndex(arr1index => arr1index[prop] == current[prop]);
    if (index == -1) {
      accumulator.push(current);
    } else {
      accumulator[index] = { ...accumulator[index], ...current }
    }

    return accumulator;
  }, arr1);
}

const arr = merge_by_property(arr1, arr2, 'name');
// output : [
//   { name: 'lang', value: 'German' },
//   { name: 'age', value: '18' },
//   { name: 'childs', value: '5' }
// ]

Using reduce and findindex. also merging all properties on both element on the list.

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
-1

//No need for using libraries and so on..
//You can just do
var arr1 = [{name: "lang", value: "English"},{name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];

const arr3 = arr1.concat(arr2);
console.log(arr3);  // final merged result will be in arr3
KASH
  • 33
  • 4