Merge objects have array, and keep both value of arrays

Viewed 247

I have 2 objects, and combine them by using jQuery.extend function.

john_5_years_ago = {
    name: "john",
    company: "google",
    languages: ["c++", "java"]
}

john_now = {
    name: "john",
    company: "facebook",
    nation: "US",
    languages: ["python", "java", "javascript"]
}

$.extend(true, {}, john_5_years_ago, john_now)

It returns result like this:

{
    name: "john",
    company: "facebook",
    nation: "US",
    languages: ["python", "java", "javascript"]
}

But I expected the value of languages array should be merged, not be overwritten. And the expected result should be like this:

{
    name: "john",
    company: "facebook",
    nation: "US",
    languages: ["python", "java", "javascript", "c++"]
}

I'll appreciate any ideas.

4 Answers

Try this:

 <!DOCTYPE html>
 <html>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
 <body>

   <p>Click the button to join two arrays.</p>

    <button onclick="myFunction()">Try it</button>

   <p id="demo"></p>

  <script>
    function myFunction() {

    john_5_years_ago = {
     name: "john",
     company: "google",
     languages: ["c++", "java"]
    }

 john_now = {
   name: "john",
   company: "facebook",
  nation: "US",
  languages: ["python", "java", "javascript"]
 }

 var children  = $.extend(true, {}, john_5_years_ago, john_now);
  console.log(children)
  children = merge_array(children.languages, john_5_years_ago.languages);
  document.getElementById("demo").innerHTML = children;
}

function merge_array(array1, array2) {
  var result_array = [];
  var arr = array1.concat(array2);
  var len = arr.length;
  var assoc = {};
    while(len--) {
      var item = arr[len];
        if(!assoc[item]) 
       { 
         result_array.unshift(item);
         assoc[item] = true;
      }
   }

  return result_array;
 } </script>

</body>
 </html>

jQuery.extend() will merge objects and deep will also work. But while merging size of the array wont change and it will not find distinct values. It will substitute those values at the indexes, that is what it does (I have included the describing demo below).

For more details refer the document as well as jQuery code

So this function will not give solution to your case, you should write a custom function (like my solution section).

And to store the deeply merged result in output you should specify it in the second parameter like $.extend(true, john_now, john_5_years_ago);

var john_5_years_ago = {
  name: "john",
  company: "google",
  languages: ["c++", "javascript", "c"],
  extra: {
    aExtra: "aExtra1 value",
    bExtra: "bExtra1 value",
    cExtra: "cExtra1 value"
  }
}

var john_now = {
  name: "john",
  company: "facebook",
  nation: "US",
  languages: ["python", "java", "c", "javascript"],
  extra: {
    aExtra: "aExtra2 value",
    cExtra: "cExtra2 value",
    zExtra: "zExtra2 value"
  }
}

$.extend(true, john_now, john_5_years_ago);
console.log(john_now);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Solution:

Use custom function to loop through those 2 objects for merging two objects deeply.

Note:-

I have also added deep parameter to specify whether the object should be copied in child levels or not.

var john_5_years_ago = {
  name: "john",
  company: "google",
  languages: ["c++", "java"],
  extra: {aExtra:"aExtra1 value", bExtra: "bExtra1 value", cExtra: "cExtra1 value"}
}

var john_now = {
  name: "john",
  company: "facebook",
  nation: "US",
  languages: ["python", "java", "javascript"],
  extra: {aExtra:"aExtra2 value", cExtra: "cExtra2 value", zExtra: "zExtra2 value"}
}

function extend(object1, object2, deep) {
  $.each(object1, function(i, key) {
    if (object1[i] instanceof Array && object2[i] instanceof Array) {
      $.each(object2[i], function(j) {
        if (object1[i].indexOf(object2[i][j]) == -1)
          object1[i].push(object2[i][j])
      });
    }else if(deep === true && object1[i].constructor==={}.constructor && object2[i].constructor==={}.constructor){
    //console.log('{}');
      extend(object1[i], object2[i]);
    } else if(object2[i] != undefined) {
      object1[i] = object2[i];
    }
  });
  $.each(object2, function(j) {
    if (object1[j] === undefined)
      object1[j] = object2[j];
  });
}
extend(john_now, john_5_years_ago, true);
console.log(john_now);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

You could write this in Plain JS:

var old = {
    name: "john",
    company: "google",
    languages: ["c++", "java"]
}

var now = {
    name: "john",
    company: "facebook",
    nation: "US",
    languages: ["python", "java", "javascript"]
}

Object.keys(old).forEach(function(prop) {
  if(now[prop] != undefined) {
    if(now["languages"] instanceof Array && old[prop] instanceof Array) {
      old[prop].forEach(function(item) {
        if(now[prop].indexOf(item) == -1) {
          now[prop].push(item);
        }
      });
    }
  } else {
    now[prop] = old[prop];
  }
});

console.log(now);

Here you go with a solution https://jsfiddle.net/6c5kgwcw/

var john_5_years_ago = {
    name: "john",
    company: "google",
    languages: ["c++", "java"]
}

var john_now = {
    name: "john",
    company: "facebook",
    nation: "US",
    languages: ["python", "java", "javascript"]
}

$.each(john_now, function(i, key){
  if(i === 'languages'){
    $.each(john_5_years_ago[i], function(j){
      if(john_now[i].indexOf(john_5_years_ago[i][j]) == -1)
     john_now[i].push(john_5_years_ago[i][j]) 
    });
  }
});

console.log(john_now);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

I've used jQuery .each method & loop through the new object.

Hope this will help you.

Related