简体   繁体   English

多数组迭代javascript

[英]multiple array iteration javascript

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} 我的第一个数组是通过以下方式组成的,对象由{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 我的第二个数组由相同的id字段和一个字符串值组成

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. 我的问题是,我需要按顺序将第一个数组的ID与第二个数组进行匹配。 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? 有没有一种更快/更有效的方法来遍历数组而无需两个forEach循环? 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! 感谢您对此的任何见解!

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. 如果您更喜欢语法,则可以使用for...of循环,但是.forEach是一个同步函数,是完全循环遍历数组的最快方法。 Also, .forEach cannot be break d so using a for...of allows you to stop the iteration after some condition succeeds if you want. 另外, .forEach不能break d,因此使用for...of允许您在某些条件成功后停止迭代(如果需要)。

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 如果您尝试从数组中查找一组特定的项目,则可能需要使用.filter.map.find.some.every

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. 很好地使用本机的for..loop会更快地产生相同的结果,因为forEach方法只是针对数组的相同实现。 If you prefer speed over expressiveness then go for the for..loop 如果您更喜欢速度而不是表现力,那就去for..loop

Check out this perf 看看这个PERF

🚀 The fast search would be if you reduce the larger arrays into object. search快速搜索将是将较大的数组缩小为对象。 And then you can refer to it by id. 然后您可以通过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: 我不知道您的if语句中有什么条件,但是假设我们要合并两个数组,则可能是这样的:

  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 总迭代将等于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 📈: 我不知道为什么会出现缺点,但是提供的解决方案有效(至少快100倍),您可以通过运行基准测试check进行检查:

 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`) 

Actually, your code runs in O(n^2) complexity. 实际上,您的代码以O(n^2)复杂度运行。

What you can do is: 您可以做的是:

  1. sort arr1 and arr2 using mergesort 使用mergesortarr1arr2进行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) . 在这种方法中,您将获得O(n*logn + n*logn + n) ,从而得出O(n*logn)

Since the id property is supposed to be unique, why not taking advantage of native javascript objects like this : 由于id属性应该是唯一的,所以为什么不利用此类本地javascript对象:

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 . 我认为这是最快的方法。

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 使用此测试套件https://jsperf.com/merging-two-arrays-with-props验证目标浏览器中不同方法的性能
  2. Use best approach 使用最佳方法

NOTES 笔记

  • unedited test suite is executed with 10000 items 未编辑的测试套件执行10000个项目
  • 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) 开放DEV工具的性能通常较小(小得多)

== UPDATE == ==更新==

Test results: 检测结果:

  • Chrome gives better performance in "convert one array to Object" approach Chrome通过“将一个数组转换为对象”方法提供了更好的性能
  • Edge gives better performance in "sort both arrays" approach Edge在“对两个数组排序”方法中提供了更好的性能
  • Safari on mac has almost same performance in both "convert one array to Object" and "sort both arrays" approaches (winners in chrome&edge) Mac上的Safari在“将一个数组转换为对象”和“对两个数组进行排序”的方法上几乎具有相同的性能(chrome&edge的赢家)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM