最快的 JavaScript 求和

IT技术 javascript arrays function
2021-02-23 07:13:12

在 JavaScript 中总结数组的最快方法是什么?快速搜索会转换几种不同的方法,但如果可能的话,我想要一个本机解决方案。这将在 SpiderMonkey 下运行。

我一直在使用的非常内在的思考:

var count = 0;
for(var i = 0; i < array.length; i++)
{
    count = count + array[i];
}

我确信有比直接迭代更好的方法。

6个回答

您应该可以使用reduce.

var sum = array.reduce(function(pv, cv) { return pv + cv; }, 0);

来源

加上ES6 中引入的箭头函数,就更简单了:

sum = array.reduce((pv, cv) => pv + cv, 0);
@Tim:同样,这是在 SpiderMonkey 下运行的,而不是任何特定的浏览器。
2021-04-19 07:13:12
@BrunoLM 这不再是真的!
2021-04-29 07:13:12
啊,对不起,我错过了。在这种情况下,这就是答案。
2021-04-30 07:13:12
根据链接的文档,“[reduce] 可能不适用于所有浏览器”
2021-05-06 07:13:12
不知何故,我怀疑它,即使reduce是本机功能。在 JS 中面向性能的代码中,避免函数调用几乎总是更快,
2021-05-14 07:13:12

改进


你的循环结构可以做得更快:


   var count = 0;
   for(var i=0, n=array.length; i < n; i++) 
   { 
      count += array[i]; 
   }

这检索array.length一次,而不是每次迭代。优化是通过缓存值进行的。


如果你真的想加快速度:


   var count=0;
   for (var i=array.length; i--;) {
     count+=array[i];
   }

这相当于一个while反向循环。它缓存该值并与 0 进行比较,从而加快迭代速度。

有关更完整的比较列表,请参阅我的JSFiddle
注意: array.reduce 在那里很糟糕,但在 Firebug 控制台中它是最快的。


比较结构

我开始了一个用于数组求和JSPerf它是快速构建的,不能保证完整或准确,但这就是编辑的目的:)

你的for循环几乎相等。我测试过,有时增加的速度比减少的要快。Array.reduce 非常慢。jsperf.com/array-reduce-vs-foreach/2
2021-04-24 07:13:12
链接的 JS Fiddle 在“For Loop: Length Caching (reverse)”中有一个错误。它总是将索引 0 处的元素添加到总和中。for (var i = 0, n = array.length; n > i; n--) { sum += array[i]; }应该改为for (var i = 0, n = array.length-1; n >= i; n--) { sum += array[n]; }. 这使它与其他缓存循环处于同一范围内。
2021-04-30 07:13:12
@BrunoLM:你说得对,这是 3 年前的旧答案。我想不久之后,有一些新的 JS 引擎可用,并且现有的引擎已经过调整,因此前向循环比反向循环更快。这说明了为什么微观优化通常是不明智的。我会继续测试和基准测试——如果你没有本地套件,jsperf 是一个很好的站点。
2021-05-13 07:13:12

在寻找对数组求和的最佳方法时,我编写了一个性能测试。

在 Chrome 中,“减少”似乎要优越得多

我希望这有帮助

// Performance test, sum of an array
  var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  var result = 0;
// Eval
  console.time("eval");
  for(var i = 0; i < 10000; i++) eval("result = (" + array.join("+") + ")");
  console.timeEnd("eval");
// Loop
  console.time("loop");
  for(var i = 0; i < 10000; i++){
    result = 0;
    for(var j = 0; j < array.length; j++){
      result += parseInt(array[j]);
    }
  }
  console.timeEnd("loop");
// Reduce
  console.time("reduce");
  for(var i = 0; i < 10000; i++) result = array.reduce(function(pv, cv) { return pv + parseInt(cv); }, 0);
  console.timeEnd("reduce");
// While
  console.time("while");
  for(var i = 0; i < 10000; i++){
    j = array.length;
    result = 0;
    while(j--) result += array[i];
  }
  console.timeEnd("while");

评估:5233.000 毫秒

循环:255.000 毫秒

减少:70.000 毫秒

同时:214.000 毫秒

嗯,不确定,试试没有 parseInt .. 我 4 年前写过这个:D
2021-04-26 07:13:12
谢谢你,为什么parseInt在reduce函数中需要a 我试过了,我的代码中也需要它。
2021-05-04 07:13:12

或者你可以用邪恶的方式来做。

var a = [1,2,3,4,5,6,7,8,9];

sum = eval(a.join("+"));

;)

也称为 LISP 方式:)
2021-04-16 07:13:12
永远不应该使用 eval()
2021-05-05 07:13:12

最快的循环,根据这个测试是反向的while循环

var i = arr.length; while (i--) { }

所以,这个代码可能是你能得到的最快的

Array.prototype.sum = function () {
    var total = 0;
    var i = this.length; 

    while (i--) {
        total += this[i];
    }

    return total;
}

Array.prototype.sum 将 sum 方法添加到数组类中……您可以轻松地将其设为辅助函数。

似乎将 while 条件评估为布尔值使其更快jsperf.com/while-bool-vs-while
2021-04-19 07:13:12
:) 是的,也不是每次都这样。尽管如此,for(var i=0,n=a.length;i<n;i++){}由于启动/停止控制结构,我更有可能使用
2021-04-28 07:13:12
方法arr从哪里来sum如果arr真的是this
2021-04-28 07:13:12
我的反转稍微快一点,比不快的次数多。
2021-04-30 07:13:12
@vol7ron,非常,非常,非常微不足道,我们正在谈论 1000 条记录中的约 1 毫秒
2021-05-10 07:13:12