【问题标题】:multiple array iteration javascript多个数组迭代javascript
【发布时间】:2025-12-25 19:35:12
【问题描述】:

在遍历两个不同的数组时,我有一个严格基于性能的问题。

我的第一个数组是按以下方式组成的,对象由一个 {id, number} 组成

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

我的第二个数组由相同的 id 字段和一个字符串值组成

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

我的问题是,我需要将第一个数组中的 id 与第二个数组按该顺序进行匹配。我用以下方式编写了我的代码。

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

有没有更快/更有效的方法来遍历数组而无需两个 forEach 循环?还是该配置是比较所有值的最佳方法?

我编写的代码可以正常工作并且返回没有问题,但我不禁想到这里有更快(性能方面)的方法或方法来做同样的事情......

感谢您对此的任何和所有见解!

【问题讨论】:

  • id 对于每个数组是否都是唯一的?
  • id是升序吗?如果是,则获取 arr1 的 id 并在不循环的情况下访问 arr2 的确切位置
  • id 排序在arr1 中吗?
  • 这是一个主要基于意见的问题,因为您将获得很多基于经验等的意见。因此,这问题应该结束了。

标签: javascript arrays iteration performance-testing


【解决方案1】:

如果您更喜欢语法,可以使用for...of 循环,但.forEach 是一个同步函数,是完全循环数组的最快方法。此外,.forEach 不能是 breakd,因此使用 for...of 可以让您在某些条件成功后停止迭代。

如果您尝试从数组中查找特定的一组项目,您可能需要使用 .filter.map.find.some.every

【讨论】:

    【解决方案2】:

    使用本机 for..loop 会更快地产生相同的结果,因为 forEach 方法只是相同的实现,但用于数组。如果您更喜欢速度而不是 表现力,那么请选择 for..loop

    看看这个perf

    【讨论】:

      【解决方案3】:

      实际上,您的代码以 O(n^2) 复杂度运行。

      你可以做的是:

      1. 使用mergesortarr1arr2进行排序
      2. 然后逐一比较相同的索引

      在这种方法中,您将获得O(n*logn + n*logn + n),从而产生O(n*logn)

      【讨论】:

        【解决方案4】:

        既然 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);
        

        我认为这是最快的方法。

        【讨论】:

          【解决方案5】:

          我建议你不要关心这个,直到你遇到性能问题

          如果性能问题是您的情况:

          1. 使用此测试套件在目标浏览器中验证不同方法的性能https://jsperf.com/merging-two-arrays-with-props
          2. 使用最佳方法

          注意事项

          • 未编辑的测试套件执行 10000 个项目
          • 有些方法可以分为准备和应用部分,所以如果您需要将“静态”数组多次合并到其他方法中 - 性能提升会很大
          • 使用开放式 DEV 工具的性能通常更小(小得多)

          == 更新 ==

          测试结果:

          • Chrome 在“将一个数组转换为对象”方法中提供了更好的性能
          • Edge 在“对两个数组都排序”方法中提供了更好的性能
          • Mac 上的 Safari 在“将一个数组转换为对象”和“对两个数组进行排序”方法中的性能几乎相同(chrome&edge 中的获胜者)

          【讨论】:

            【解决方案6】:

            ? 如果将较大的数组缩减为对象,则可以快速搜索。然后就可以通过id来引用了。

            我不知道你在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)

            总迭代将等于arr1.length + arr2.length

            更新

            我不知道为什么会有缺点,但是提供的解决方案正在运行(至少快 100 倍),您可以通过运行基准测试来检查它?:

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

            【讨论】:

              最近更新 更多