2

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}]
1
  • 1
    I am looking for answer to do it using underscorejs, I am not familiar with that library Commented Sep 21, 2015 at 17:46

4 Answers 4

9

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/

Sign up to request clarification or add additional context in comments.

3 Comments

No problem! I reckon the document is quite nice once you get use to it
@AurélienThieriot: Nice use of findWhere! Your solution is 145% faster than mine :-p jsperf.com/underscore-merge
@AurélienThieriot: My modified solution is now 48% faster. :)
3

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]]);
  });
}

Comments

0

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.

Comments

0

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];
    });
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.