4

I have two object arrays (which I receive from a server based on some user input):

array1 = [{id:1, name:Bob}, {id:2, name:John}, {id:3, name:Mary}];
array2 = [{id:2, field:true},{id:2, field:true}, {id:3, field:false}];

The id's in both array correspond to each other (they are user ids). In real life these arrays will be much larger (up to 8000 elements in array 1, and 16000 in array2).

The thing I need to accomplish is on the front end I am currently showing just array2 information which displays to the user id and the field. The problem is the front end user doesn't know anyone by their user id instead they know them by their name. I need an array which has objects which look like this: {id:'',name:'',field:''}.

My first thought was to create a new array and "combine the two arrays" :

var new_array = [];

for (var i = 0; i < array2.length; i++) {
  var name = 'Unknown';
  for (var j = 0; j < array1.length; j++) {

    if (array1[j].id === array2[i].id) {
      name = array1[j].name;
    }

    this.new_array.push({
      id: array2[i].id,
      name: name,
      field: array1[j].field
    });
  }
}

So I loop through the the second array and check if the id matches the id of the first array. If it does I take the name from the first array and that is the user's name so that is how I get the user's name.

This works, but it is kind of slow on the front end, it take a few seconds to do this and if there are many items the user experience doesn't feel good there is a lot of waiting. I am looking for a more efficient way to do what I need to do.

crackmigg
  • 5,571
  • 2
  • 30
  • 40
user2924127
  • 6,034
  • 16
  • 78
  • 136
  • 1
    In your example, `array1`'s indexes are consistent with their IDs (if off by 1). Is this true in your actual arrays? – Jesse Kernaghan Mar 29 '16 at 21:36
  • Yes, the index and the id's have nothing in common. Actually the user id's are 8 digit numbers and in array1 they can be returned in any order from the server. – user2924127 Mar 29 '16 at 21:38
  • The code as you posted it will push a new value into `new_array` for every value of array2 and, for each of those, for every value of array1. Thus, the length of `new_array` would be `array1.length * array2.length`, or to use your sample numbers, `8000 * 16000` or 128 million entries. Is that really how it works, or do you actually only want to merge by matching "id" value? – Pointy Mar 29 '16 at 21:52
  • Are the arrays both sorted by id? Do the arrays both contain the corresponding items in exactly the same order (and only them)? – Bergi Mar 29 '16 at 22:26
  • Closely related, if not duplicate: http://stackoverflow.com/q/4856717/1048572 – Bergi Mar 29 '16 at 22:31

1 Answers1

4

Run through one array and create an object to map id values to entries:

var array2idx = array2.reduce(function(map, value) {
  map[value.id] = value;
  return map;
}, {});

Now you can find the array2 values with a simple lookup:

var new_array = [];
for (var i = 0; i < array1.length; i++) {
  var v2 = array2idx[array1[i].id];
  if (v2) {
    new_array.push({
      id: v2.id,
      name: array1[i].name,
      field: array1[i].field
    });
  }
}

That should be considerably faster. Looking up an id in the index object will take almost no time at all.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Note that this sample code assumes that what the OP really wants is to do something like a SQL `JOIN` operation between the two arrays, on the "id" property. The code in the question does a cross product but I doubt that's what's actually desired. – Pointy Mar 29 '16 at 21:53
  • 1
    Simplified, this solution is O(n+m) compared to the original O(n*m). – James Buck Mar 29 '16 at 22:01