0

I have a question strictly based in regards to performance while iterating through two different arrays.

My first array is composed in the following way, objects consisting of an {id, number}

var arr1 = [{id: 1, number: 7}, {id: 2, number: 5}];

My second array is composed of the same id field, and a string value

var arr2 = [{id: 2, string: 'foo'}, {id: 1, string: 'bar'}];

My question is this, I need to match the id's from the first array with the second array specifically in that order. I wrote my code in the following manner.

arr1.forEach(function(x){
   arr2.forEach(function(y){
      if(condition){
         Do something...
      }
   });
});

Is there a faster/more effective way to iterate through the arrays without two forEach loops? Or is that configuration the best method for comparing all the values?

The code I wrote works and returns no problem, but I can't help thinking there's a faster (performance wise) method or means of doing the same thing here...

Thanks for any and all insight in regards to this!

Edward H
  • 19
  • 8

6 Answers6

2

You can use a for...of loop if you like the syntax better, but .forEach is a synchronous function and is the fastest way to completely loop through the arrays. Also, .forEach cannot be breakd so using a for...of allows you to stop the iteration after some condition succeeds if you want.

If you're trying to find a specific set of items from within the arrays, you may want to use .filter, .map, .find, .some, or .every

Meghan
  • 1,215
  • 11
  • 17
-1

Well using the native for..loop would produce the same results much faster since the forEach method is just the same implementation but for arrays. If you prefer speed over expressiveness then go for the for..loop

Check out this perf

baeyun
  • 228
  • 1
  • 6
-1

The fast search would be if you reduce the larger arrays into object. And then you can refer to it by id.

I don't have idea what condition you have in your if statement, but assume we want to merge the two arrays, then it could be like this:

    const arr1 = [{id: 1, number: 7}, {id: 2, number: 5}]
    const arr2 = [{id: 2, string: `foo`}, {id: 1, string: `bar`}]
    const list = arr1.reduce((all, next) => {
     all[next.id] = next
     return all
    }, {})
    const merged = arr2.map(el => list[el.id] ? {...el, ...list[el.id]} : el)
    console.log(merged)

The total iteration would be equal to arr1.length + arr2.length

UPDATE

I don't know why I get minuses, but the offered solution is working (at least 100 times faster), you can check it by running the benchmark :

const arr1 = []
for (let id = 0; id <= 100000; id++) {
  const number = Math.round(Math.random() * 100);
  arr1.push({ id, number })
}

const arr2 = []
for (let id = 1000; id > 0; id--) {
  const string = id % 2 === 0 ? `foo_${id}` : `bar_${id}`
  arr2.push({ id, string })
}

// Nested loops
console.time(`nestedLoops`)
const merged = []
arr2.forEach(x => {
  arr1.forEach(y => {
    if (x.id === y.id) {
      merged.push({
        id: x.id,
        string: x.string,
        number: y.number,
      });
    }
  });
});
console.timeEnd(`nestedLoops`)

// Array to object then a loop
console.time(`array2object`)
const merged2 = []
const list = arr1.reduce((all, next) => {
  all[next.id] = next;
  return all;
}, {});
arr2.forEach(x => list[x.id] &&
  merged2.push({
    id: x.id,
    string: x.string,
    number: list[x.id].number
  })
);
console.timeEnd(`array2object`)
sultan
  • 4,543
  • 2
  • 24
  • 32
-1

Actually, your code runs in O(n^2) complexity.

What you can do is:

  1. sort arr1 and arr2 using mergesort
  2. compare then one by one by same index

In this approach you will get O(n*logn + n*logn + n), resulting in O(n*logn).

guijob
  • 4,413
  • 3
  • 20
  • 39
-1

Since the id property is supposed to be unique, why not taking advantage of native javascript objects like this :

var objects1 =  {
    id_1: {number: 7},
    id_2: {number: 5}
};

var objects2 = {
    id_2: {string: 'foo'},
    id_1: {string: 'bar'}
};

console.log(objects1.id_1.number + ' | ' + objects2.id_1.string);

I think this is the fastest way to do that .

CryptoBird
  • 508
  • 1
  • 5
  • 22
-1

I would suggest you don't care about this, until you get performance issues

If the performance issue is the your case:

  1. Validate performance of different approaches in target browsers using this test suite https://jsperf.com/merging-two-arrays-with-props
  2. Use best approach

NOTES

  • unedited test suite is executed with 10000 items
  • some approaches could be divided into preparation and applying parts, so if you need to merge "static" array several times into others - the performance gain will be great
  • performance with open DEV tools usually is smaller (much smaller)

== UPDATE ==

Test results:

  • Chrome gives better performance in "convert one array to Object" approach
  • Edge gives better performance in "sort both arrays" approach
  • Safari on mac has almost same performance in both "convert one array to Object" and "sort both arrays" approaches (winners in chrome&edge)
Andrii Muzalevskyi
  • 3,261
  • 16
  • 20