0

I would like to merge 2 arrays of hashes into 1 new array using JS, Underscore or JQuery.

Those 2 arrays could be different length and merge will be based on id attribute. Hashes in between same arrays may not have same id's , example:

arr1 id's = [1,5]

arr2 id's = [1,2]

Here are my arrays:

arr1 = [{
    id: 1
    name: 'fred'
},id: 5
    name: 'alex'
}];

arr2 = [{
    id: 1
    wage: '300'
},{
    id: 2
    wage: '10'
}]

so based on id attribute i should get following:

arr3 = [{
    id: 1
    name: 'fred'
    wage: '300'
},{
    id: 2
    wage: '10'
},{
    id: 5
    name: 'alex'
}]

I tried with Merging/extend javascript object arrays based on join of a key property in each but if arrays are not same length it doesn't work. Any help?

Community
  • 1
  • 1
Mil
  • 59
  • 8
  • 3
    [JavaScript merging objects by id](http://stackoverflow.com/q/19480008/1529630) – Oriol Jun 26 '16 at 23:43
  • @Mil - please clarify whether this needs to take into absolute account the `id` index, for example see my answer. You mention it, but not clear in example data or question, so update OP please. http://stackoverflow.com/help/how-to-ask – Daniel Brose Jun 26 '16 at 23:49
  • 1
    For an answer, consider that this is obvious duplicate post and see @Oriol link. You can self answer and accept that, though compare those answers to others provided here before doing so – Daniel Brose Jun 26 '16 at 23:58
  • HI Daniel, thank you for helping with this one, but Oriol's suggestion didn't fix my problem (tried best answer). I also updated question maybe it is clearer now, i think @charlietfl got my point since i didn't explain it well in start - indexing could be different – Mil Jun 27 '16 at 00:26

3 Answers3

2

You can use Object.assign:

arr1 = [{ id: 1, name: 'fred' }];

arr2 = [
  { id: 1, wage: '300' }, 
  { id: 2, wage: '10' }
];

var result = [];
arr1.concat(arr2)
  .forEach(item =>
    result[item.id] =
    Object.assign({}, result[item.id], item)
  );
result = result.filter(r => r);
console.log(result)
Morteza Tourani
  • 3,506
  • 5
  • 41
  • 48
  • When i try to convert this to coffeescript i get error because of fat arrow, could you explain you answer so i can convert it please? – Mil Jun 26 '16 at 23:40
  • This is simple first concatenate all your arrays and then use Object.assign to do then merge for you. Because the id is integer I used id as index of array and each time I change value of index with current value merge with item value. Consider to apply edit. – Morteza Tourani Jun 26 '16 at 23:46
  • @mertezaT thank you, this worked very well, actually since indexing is based on int value can this work on strings? For example: id: "1" instead of id: 1 since i need string values not integers – Mil Jun 27 '16 at 20:21
1

EDIT

This solution, as noted in comments, does NOT account for matching via id. To see this in action, just add { id:7, name: 'wilma' } to first array.

Im leaving it here however as it was NOT clear from example data or description this was key issue from the OP, though part fault on my part aswell. However I will comment there and if he says it is I may edit or remove this then


jQuery.extend()

https://api.jquery.com/jquery.extend/

jQuery.extend( [deep ], target, object1 [, objectN ] )

Passing in that extra param makes it a deep merge, ie recursive

https://jsfiddle.net/dabros/q0hhqbmf/

arr1 = [{
    id: 1,
    name: 'fred'
}];

arr2 = [{
    id: 1,
    wage: '300'
},{
    id: 2,
    wage: '10'
}]

arr3 = [];

// Use 2 extends, though $.merge(x,$.extend(y,z)) would work just as well in this case
$.extend(arr3, $.extend(true, arr1, arr2 ));

console.log(arr3);
Daniel Brose
  • 1,394
  • 10
  • 24
  • Fails when arrays not same length and indexing is different. Add `{ id:7, name: 'wilma' }` to first array – charlietfl Jun 26 '16 at 23:41
  • @charlietfl - run that code, it merged perfect in jsfiddle, all indexes and with exact data like that – Daniel Brose Jun 26 '16 at 23:42
  • 1
    Yeah but it only matches index...try adding object I just commented into first array. OP stated array lengths won't match – charlietfl Jun 26 '16 at 23:43
  • Unfortunately it's not smart enough to match based on common property value – charlietfl Jun 26 '16 at 23:47
  • @charlietfl - I actually didnt see that as part of OP, and reading OP again I still dont. I updated this and will comment there to ask that, then look again – Daniel Brose Jun 26 '16 at 23:48
  • I'm basing it off title...not trying to bust balls...just pointing out potential issue/limitation – charlietfl Jun 26 '16 at 23:49
  • @charlietfl - thanks for that, thats the OP problem for not clarifying, rather than removing lets help him actually fix it by using this as example – Daniel Brose Jun 26 '16 at 23:52
  • @charlietfl Sorry if I didn't make it clear, i need to merging to be based on 'ID' – Mil Jun 26 '16 at 23:55
  • @DanielBrose Sorry for confusion, i need merging to be based on 'ID' attribute – Mil Jun 26 '16 at 23:56
  • @Mil - i figured that, please see my comment on OP and update data and description there to be clearer please – Daniel Brose Jun 26 '16 at 23:57
0

Why not just simply iterate them, and collect in new array?

<script src="https://raw.githubusercontent.com/lodash/lodash/4.13.1/dist/lodash.js"></script>
<script>
var arr1 = [
  {
    id: 1,
    name: 'fred'
  },
  {
    id: 5,
    name: 'alex'
  }
];

var arr2 = [
  {
    id: 1,
    wage: '300'
  },
  {
    id: 2,
    wage: '10'
  }
];
  
var a1, a2, arr3 = [], merged = [];
  
// finding intersection and merging
for(a1 = 0; a1 < arr1.length; a1++) {
  for(a2 = 0; a2 < arr2.length; a2++) {
    if(arr1[a1].id === arr2[a2].id) {
      arr3.push(_.extend(arr1[a1], arr2[a2]));
      merged.push(arr1[a1].id);
      break
    }
  }
}

// finding non merged elements and adding
for(a1 = 0; a1 < arr1.length; a1++) {
  if(merged.indexOf(arr1[a1].id) > -1) {
    continue;  
  }
  
  arr3.push(arr1[a1]);
}

// finding non merged elements and adding
for(a2 = 0; a2 < arr2.length; a2++) {
  if(merged.indexOf(arr2[a2].id) > -1) {
    continue; 
  }
  
  arr3.push(arr2[a2]);
}

document.write(JSON.stringify(arr3));
</script>
num8er
  • 18,604
  • 3
  • 43
  • 57