Tomislav
Tomislav

Reputation: 3211

Combine two arrays of objects using underscore

I have two array of objects:

var a = [{id:456, name:'sojuz'},
         {id:751, name:'sputnik'},
         {id:56, name:'arianne'}]

var b = [{id:751, weight:5800},
         {id:456, weight:2659},
         {id:56, weight:6700}]

Using underscorejs how to extend array a into new array c adding weight property from array b where the id property is the same:

var c = [{id:456, name:'sojuz', weight:2659},
         {id:751, name:'sputnik', weight:5800},
         {id:56, name:'arianne', weight:6700}]

Upvotes: 2

Views: 4468

Answers (4)

Aurélien Thieriot
Aurélien Thieriot

Reputation: 5923

This is one way of doing it with underscore:

var c = _.map(a, function(element) {
    var treasure = _.findWhere(b, { id: element.id });

    return _.extend(element, treasure);
});

If you want to fiddle (See what I did there) with it: http://jsfiddle.net/b90pyxjq/3/

Upvotes: 9

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48751

You can map (_.map) each of the indexed (_.indexBy) objects in list a and list b to an extended object (_.extend) to produce a list of merged objects.

The following solution below utilizes the Underscore.js library.

var a = [
  { id: 456, name: 'sojuz' },
  { id: 751, name: 'sputnik' },
  { id: 56,  name: 'arianne' }
];

var b = [
  { id: 751, weight: 5800 },
  { id: 456, weight: 2659 },
  { id: 56,  weight: 6700 }
];

function mergeLists(listA, listB, idField) {
  var indexA = _.indexBy(a, idField)
  var indexB = _.indexBy(b, idField);

  return _.map(indexA, function(obj, key) {
    return _.extend(obj, indexB[key]);
  });
}

var c = mergeLists(a, b, 'id');

document.body.innerHTML = JSON.stringify(c, null, ' ');
body {
  white-space: pre;
  font-family: monospace;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Edit

I have modified my original example above, by eliminating the unnecessary indexing of the a list. My solution runs more efficiently than Aurélien Thieriot's solution above and it is roughly 48% faster.

You can see it in action here: http://jsperf.com/underscore-merge/3

function mergeLists3(listA, listB, idField) {
  var indexB = _.indexBy(listB, idField);

  return _.map(listA, function(obj, key) {
    return _.extend(obj, indexB[obj[idField]]);
  });
}

Upvotes: 3

DanRegep
DanRegep

Reputation: 7

Copy any property name without underscore using ES6 or using ES5 with polyfilled replacements:

a.map(function (aItem) {
    var found = b.find(function (bItem) {
        if (aItem.id == bItem.id) return true;
    }) || {};

    Object.getOwnPropertyNames(found).map (function (property) {
        aItem[property] = found[property];
    });
});

Upvotes: 0

Mario Mucalo
Mario Mucalo

Reputation: 635

Something like this can work, but is definitely not optimal:

var c = [];
for(var i = 0; i < a.length; i++) {
   for (var j = 0; j < b.length; j++) {
      if(b[j].id == a[i].id) {
        var newC = {
          id: a[i].id,
          name: a[i].name,
          weight: b[j].weight
        }
        c.push(newC);
        break;
      }
   }
}

However, this does have O(n^2) complexity, I'm sure it can be optimized.

Upvotes: 0

Related Questions