benhowdle89
benhowdle89

Reputation: 37504

Extend and merge two arrays (that contain objects) in JS

So I have array A:

   var arrA = [{
      name: 'twitter',
      location: 0,
      hidden: false,
      href: "https://twitter.com/i/connect"
    }, {
      name: 'medium',
      location: 1,
      hidden: false,
      href: "https://medium.com/me/activity"
    }
  ];

And array B:

var arrB = [{
      name: 'twitter',
      location: 1,
      hidden: false
    }, {
      name: 'medium',
      location: 0,
      hidden: false
    }
  ];

How can I end up with an array that looks like this:

var newArr = [{
      name: 'twitter',
      location: 1,
      hidden: false,
      href: "https://twitter.com/i/connect"
    }, {
      name: 'medium',
      location: 0,
      hidden: false,
      href: "https://medium.com/me/activity"
    }
  ];

So, two things here, 1. the location values have been taken from arrB, not arrA, 2. that newArr's objects now contain href keys, taken from arrA.

So values I need from the second array, but new keys are maintained from the first array.

Can I do this with an underscore.js function (I'm using _.extend right now, but it doesn't maintain the key from arrA if it's new)?

Upvotes: 2

Views: 1315

Answers (4)

user663031
user663031

Reputation:

You can "map" entries in arrA into themselves merged with the corresponding entries in arrB. In Underscore:

_.map(arrA, function(a) {
    return _.extend(a, _.find(arrB, function(b) {
        return a.name === b.name;
    }));
});

This solution has the charateristics that:

  1. The objects may be appear in any order in the two arrays; they are matched up by name.
  2. Any extra properties in the objects in array b will be copied over.

In native JS

arrA.map(function(a) {
    return Object.assign(a, arrB.find(function(b) {
        return a.name === b.name; 
    }));
});

Object.assign and Array.find, if not available, can be polyfilled. For example, here's a version of find:

Array.prototype.find = function(callback) {
    for (var i = 0; i < this.length; i++ ) {
        if (callback(this[i], i, this)) return this[i];
    }
 });

Upvotes: 0

agershun
agershun

Reputation: 4107

You can join two arrays and select proper attributes with Alasql library:

var res1 = alasql('SELECT arrA.name, arrB.location, arrA.href, arrB.hidden \
            FROM ? arrA JOIN ? arrB USING name', [arrA,arrB]);

Or Underscore _.extend version of this:

alasql.fn.extend = _.extend.bind(_);
var res2 = alasql('SELECT COLUMN extend(arrA._, arrB._) 
                   FROM ? arrA JOIN ? arrB USING name', [arrA,arrB]);

Try these examples at jsFiddle.

Upvotes: 1

Diode
Diode

Reputation: 25165

Not sure whether underscore has a function to merge the arrays like this, but you can write a function as given below to merge the arrays conditionally

Array.prototype.conditionalMerge = function(arr, props){

    var merged = [];

    for(var i=0; i<this.length;i++){
        var item = {};
        for(var attr in this[i]){
            item[attr] = (props[attr])?arr[i][attr]:this[i][attr];
        }
        merged.push(item);
    }

    return  merged;
}

arrA.conditionalMerge(arrB, {location:true})

Upvotes: 0

JOE LEE
JOE LEE

Reputation: 1058

var newArr=[];
$.each(arrA, function(index, value) {
$.extend(value, arrB[index]);
newArr[index]=value
});

http://jsfiddle.net/QZzZM/

Upvotes: 0

Related Questions