多个数组迭代javascript

时间:2018-03-10 17:10:19

标签: javascript arrays iteration performance-testing

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

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

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

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

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

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

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

在没有两个forEach循环的情况下,是否有更快/更有效的方法来迭代数组?或者该配置是比较所有值的最佳方法?

我写的代码工作并没有问题,但我不禁想到有一个更快(表现明智)的方法或在这里做同样事情的方法......

感谢您对此有任何见解!

6 个答案:

答案 0 :(得分:0)

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

如果您尝试在阵列中查找特定的一组项目,则可能需要使用.map.find.some.every ,或{{1}}

答案 1 :(得分:-1)

使用本机for..loop可以更快地生成相同的结果,因为forEach方法只是相同的实现,但对于数组。如果您更喜欢速度超过表现力,请转到for..loop

查看此perf

答案 2 :(得分:-1)

快速搜索是将较大的数组减少为对象。然后你可以通过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`)

答案 3 :(得分:-1)

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

你能做的是:

  1. 使用arr1
  2. arr2mergesort进行排序
  3. 然后逐个比较相同的索引
  4. 在这种方法中,您将获得O(n*logn + n*logn + n),从而产生 O(n*logn)

答案 4 :(得分:-1)

由于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)

我建议您不要关心这一点,直到遇到性能问题

如果遇到性能问题:

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

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

    == UPDATE ==

    测试结果:

    • Chrome在“将一个数组转换为对象”方法中提供了更好的性能
    • Edge在“排序两个阵列”方法中提供了更好的性能
    • Mac上的Safari在“将一个数组转换为对象”和“对两个数组进行排序”方法(在chrome和&amp; edge中获胜)方面具有几乎相同的性能
相关问题