1

I have 2 arrays of objects:

var a = [
    { "image_id": 631293, "score": 73 }, 
    { "image_id": 11848407, "score": 56 }
];

var b = [
    { "image_id": 631293, "article_id": 173 }, 
    { "image_id": 11848407, "article_id": 121 }
];

I have tried to apply method described in How can i merge array of objects with underscore js but unfortunately it does not work at all.

My need is to merge both arrays of objects thanks to image_id.

So I tried this :

_.values(
   _.extendOwn(
      _.indexBy(a, 'image_id'),
      _.indexBy(b, 'image_id')
   )
)

but output just return me this array of object a

I need to get :

[
    {"image_id": 631293, "score": 73, "article_id": 173}, 
    {"image_id": 11848407, "score": 56, "article_id": 121}
]

How can I achieve this without doing a loop to check every element of array and use a findWhere?

Community
  • 1
  • 1
Toucouleur
  • 1,194
  • 1
  • 10
  • 30

2 Answers2

3

Using indexBy is a good start. Then loop and extend one:

var indexed = _.indexBy(a, 'image_id');

_.each(b, function(obj) {
  var master = indexed[obj.image_id];
  if (master) _.extend(master, obj);
});

or if you want a new array and let the original objects untouched:

var result = _.map(b, function(obj) {
  var master = indexed[obj.image_id];
  return _.extend({}, master, obj);
});

var a = [{
  "image_id": 11848407,
  "score": 56
}, {
  "image_id": 631293,
  "score": 73
}, {
  "image_id": "dummy",
  "score": 1
}];

var b = [{
  "image_id": "test",
  "article_id": 0
}, {
  "image_id": 631293,
  "article_id": 173
}, {
  "image_id": 11848407,
  "article_id": 121
}];

var indexed = _.indexBy(a, 'image_id');

_.each(b, function(obj) {
  var master = indexed[obj.image_id];
  if (master) _.extend(master, obj);
});

console.log(a);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
1

You can use _.zip as follows:

var a = [
  { "image_id": 631293, "score": 73 }, 
  { "image_id": 11848407, "score": 56 }
];

var b = [
  { "image_id": 631293, "article_id": 173 }, 
  { "image_id": 11848407, "article_id": 121 }
];

var c = _.zip(a, b).map(function(elem){
  return _.extendOwn(elem[0], elem[1]);
});
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Kalman
  • 8,001
  • 1
  • 27
  • 45
  • Thanks for this great tip! – Toucouleur Nov 21 '16 at 17:27
  • 1
    @Toucouleur This doesn't work if they're not ordered as it doesn't take the `image_id` into account. – Emile Bergeron Nov 21 '16 at 17:28
  • 1
    This will work **only** if the source arrays happen to be sorted and a one for one match. Basically, this is not your solution. – JonSG Nov 21 '16 at 17:30
  • Agreed with the commenters. This WILL work for THIS question, but only because the array elements in both arrays are matching up, which is a great use case for the _.zip as described in documentation http://underscorejs.org/#zip – Kalman Nov 21 '16 at 17:34