4

I am wanting to merge the following object arrays, by first joining on the id property

var arr1 = [{
    id: 1,
    name: 'fred',
    title: 'boss'
},{
    id: 2,
    name: 'jim',
    title: 'nobody'
},{
    id: 3,
    name: 'bob',
    title: 'dancer'
}];

var arr2 = [{
    id: 1,
    wage: '300',
    rate: 'day'
},{
    id: 2,
    wage: '10',
    rate: 'hour'
},{
    id: 3,
    wage: '500',
    rate: 'week'
}];

So the result would be

[{
    id: 1,
    name: 'fred',
    title: 'boss',
    wage: '300',
    rate: 'day'
},{
    id: 2,
    name: 'jim',
    title: 'nobody',
    wage: '10',
    rate: 'hour'
},{
    id: 3,
    name: 'bob',
    title: 'dancer',
    wage: '500',
    rate: 'week'
}]

I would like to avoid using js frameworks (if possible), although ExtJs is already part of the project. AT the moment I have a loop with an inner loop that if the keys match it copies the properties and breaks out of the inner loop to start the next outer loop.

Any better suggestions?

David
  • 8,340
  • 7
  • 49
  • 71
  • This would be relatively easy to do with jQuery with the help of `.extend` -- anyhow, can you show the code you have so far, and does it work? Are you looking for an optimized solution? – Gary Green May 19 '11 at 13:30

3 Answers3

4

Like this?

var combined = [];
function findSecond(id,second){
    for (var i=0;i<second.length;i++){
        if(second[i].id === id){
            return second[i];
        }
    }
    return null
}

while (el = arr1.pop()){
    var getSec = findSecond(el.id,arr2);
    if (getSec){
        for (var l in getSec){
            if (!(l in el)) {
                el[l] = getSec[l];
            }
        }
        combined.push(el);
    }
}

If the arrays have the same length, and the id's are equal, a simpler merge will do:

function merge(a1,a2) {
    var i = -1;
    while ((i = i+1)<a1.length)  {
     for (var l in a2[i]) {
            if (!(l in a1[i] )) {
                a1[i][l] = a2[i][l];
            }
     }
    }
   return a1; 
}

Here's a working example

[Edit 2016/07/30] Added a snippet using more functional approach and, based on @djangos comment, an extra method to combine both arrays.

(function() {
    var alert = function(str) {document.querySelector('#result').textContent += str + '\n';};
    var arrays = getArrays();
  
    alert('Combine on id (shared id\'s):')
    alert(JSON.stringify(combineById(arrays.arr1, arrays.arr2), null, ' '));
  
    alert('\nCombine on id (all id\'s):')
    alert(JSON.stringify(combineBothById(arrays.arr1, arrays.arr2), null, ' '));
  
    // for combineBothById the parameter order isn't relevant
    alert('\nCombine on id (all id\'s, demo parameter order not relevant):')
    alert(JSON.stringify(combineBothById(arrays.arr2, arrays.arr1), null, ' '));
  
    // combine first array with second on common id's
    function combineById(arr1, arr2) {
      return arr1.map(
          function (el) {
                var findInB = this.filter(function (x) {return x.id === el.id;});
                if (findInB.length) {
                    var current = findInB[0];
                    for (var l in current) {
                        if (!el[l]) {el[l] = current[l];}
                    }
                }
                return el;
          }, arr2);
    }

    // combine first array with second on all id's
    function combineBothById(arr1, arr2) {
        var combined = arr1.map(
            function (el) {
                var findInB = this.filter(function (x) {return x.id === el.id;});
                if (findInB.length) {
                    var current = findInB[0];
                    for (var l in current) {
                        if (!el[l]) {el[l] = current[l];}
                    }
                }
                return el;
            }, arr2);
        combined = combined.concat(arr2.filter(
            function (el) {
                return !this.filter(function (x) {return x.id === el.id;}).length;
            }, combined));
        return combined;
    }
  
    function getArrays() {
        return {
            arr1: [{
                id: 1,
                name: 'fred',
                title: 'boss'
            }, {
                id: 2,
                name: 'jim',
                title: 'nobody'
            }, {
                id: 3,
                name: 'bob',
                title: 'dancer'
            }],
            arr2: [{
                id: 1,
                wage: '300',
                rate: 'day'
            }, {
                id: 2,
                wage: '10',
                rate: 'hour'
            }, {
                id: 4,
                wage: '500',
                rate: 'week'
            }]
        };
    }
}());
<pre id="result"></pre>
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • I was lookign for same thing but a bit different , please check http://jsfiddle.net/ZaJ4x/35/ . I am expecting result to have ids 1,2,3,4 – django Jul 30 '16 at 06:27
  • 1
    You seem to be wanting to combine from both array. Maybe this fiddle offers a solution: http://jsfiddle.net/7aobwxvv/ – KooiInc Jul 30 '16 at 12:07
  • @django added a snippet to the answer too – KooiInc Jul 30 '16 at 12:17
2

You can merge two arrays by id column with Alasql library:

var res = alasql('SELECT * FROM ? arr1 JOIN ? arr2 USING id', [arr1,arr2]);

Try this example at jsFiddle.

agershun
  • 4,077
  • 38
  • 41
0

try this...

var arr1 = [{
    id: 1,
    name: 'fred',
    title: 'boss'
},{
    id: 2,
    name: 'jim',
    title: 'nobody'
},{
    id: 3,
    name: 'bob',
    title: 'dancer'
}];

var arr2 = [{
    id: 1,
    wage: '300',
    rate: 'day'
},{
    id: 2,
    wage: '10',
    rate: 'hour'
},{
    id: 3,
    wage: '500',
    rate: 'week'
}];

let arr5 = arr1.map((item, i) => Object.assign({}, item, arr2[i]));
console.log(arr5)
Trilok Singh
  • 1,227
  • 12
  • 10