最快的 JavaScript 求和

用 JavaScript 汇总数组的最快方法是什么?快速搜索将翻转 一些不同的方法,但是如果可能的话,我想要一个原生的解决方案。这将在 Spider Monkey 下运行。

我一直使用的内部思维方式:

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

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

179736 次浏览

您应该能够使用 reduce

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

来源

ES6中引入了 箭头函数,这样就更简单了:

sum = array.reduce((pv, cv) => pv + cv, 0);

最快的循环,根据 这个测试是反向的 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 方法... ... 您可以轻松地将其改为一个 helper 函数。

改进


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


   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进行比较,因此迭代速度更快。

有关更完整的比较列表,请参见我的 网站: http://JSFiddle.net/FZqZN/3409/”rel = “ noReferrer”> JSFiddle
注意: array.reduce 在这里非常糟糕,但是在 Firebug Console 中它是最快的。


比较结构

我为数组求和启动了 一个 href = “ http://jsPerf.com/array-sum”rel = “ norefrer”> JSPerf 。它构建得很快,不能保证完整或准确,但这就是 编辑的用途:)

对于您的特定情况,只需使用 Ararray 的 reduce方法:

var sumArray = function() {
// Use one adding function rather than create a new one each
// time sumArray is called
function add(a, b) {
return a + b;
}


return function(arr) {
return arr.reduce(add);
};
}();


alert( sumArray([2, 3, 4]) );

基于 这个测试(for-vs-forEach-vs-reduce)这(循环)

我可以说:

1 # 最快: for loop

var total = 0;


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

2 # 总计

对于您的情况,您不需要这个,但是它增加了很多灵活性。

Array.prototype.Aggregate = function(fn) {
var current
, length = this.length;


if (length == 0) throw "Reduce of empty array with no initial value";


current = this[0];


for (var i = 1; i < length; ++i)
{
current = fn(current, this[i]);
}


return current;
};

用法:

var total = array.Aggregate(function(a,b){ return a + b });

不确定的方法

然后是 forEachreduce,它们的性能几乎相同,而且不同的浏览器有所不同,但无论如何它们的性能都是最差的。

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

在 Chrome 浏览器中,“ reduce”似乎要优越得多

希望这个能帮上忙

// 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毫秒

循环: 255000毫秒

减少: 70000毫秒

同时: 214000毫秒

最简单、最快速、可重复使用和灵活的方法之一是:

Array.prototype.sum = function () {
for(var total = 0,l=this.length;l--;total+=this[l]); return total;
}


// usage
var array = [1,2,3,4,5,6,7,8,9,10];
array.sum()

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

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


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

;)

两端相加怎么样? 可以缩短一半的时间,像这样:

1,2,3,4,5,6,7,8; sum = 0

2,3,4,5,6,7,和 = 10

3,4,5,6,和 = 19

4,5; 和 = 28

和 = 37

一种算法可能是:

function sum_array(arr){
let sum = 0,
length = arr.length,
half = Math.floor(length/2)


for (i = 0; i < half; i++) {
sum += arr[i] + arr[length - 1 - i]
}
if (length%2){
sum += arr[half]
}
return sum
}

当我用 performance.now()在浏览器上测试它时,它执行得更快。 我觉得这样更好,你们觉得呢?

我尝试使用 Performance. now ()来分析不同类型循环的性能。我做了个甚大天线阵找到了数组中所有元素的总和。我每次运行代码三次,发现 为每个人减少是一个明显的赢家。

//循环

let arr = [...Array(100000).keys()]
function addUsingForLoop(ar){
let sum = 0;
for(let i = 0; i < ar.length; i++){
sum += ar[i];
}
console.log(`Sum: ${sum}`);
return sum;
}
let t1 = performance.now();
addUsingForLoop(arr);
let t2 = performance.now();
console.log(`Time Taken ~ ${(t2 - t1)} milliseconds`)


// "Sum: 4999950000"
// "Time Taken ~ 42.17500000959262 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 44.41999999107793 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 49.845000030472875 milliseconds"

//While 循环

let arr = [...Array(100000).keys()]
function addUsingWhileLoop(ar){
let sum = 0;
let index = 0;
while (index < ar.length) {
sum += ar[index];
index++;
}
console.log(`Sum: ${sum}`)
return sum;
}
let t1 = performance.now();
addUsingWhileLoop(arr);
let t2 = performance.now();
console.log(`Time Taken ~ ${(t2 - t1)} milliseconds`)


// "Sum: 4999950000"
// "Time Taken ~ 44.2499999771826 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 44.01999997207895 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 41.71000001952052 milliseconds"

//do-while

let arr = [...Array(100000).keys()]
function addUsingDoWhileLoop(ar){
let sum = 0;
let index = 0;
do {
sum += index;
index++;
} while (index < ar.length);
console.log(`Sum: ${sum}`);
return sum;
}
let t1 = performance.now();
addUsingDoWhileLoop(arr);
let t2 = performance.now();
console.log(`Time Taken ~ ${(t2 - t1)} milliseconds`)


// "Sum: 4999950000"
// "Time Taken ~ 43.79500000504777 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 43.47500001313165 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 47.535000019706786 milliseconds"

//反向循环

let arr = [...Array(100000).keys()]
function addUsingReverseLoop(ar){
var sum=0;
for (var i=ar.length; i--;) {
sum+=arr[i];
}
console.log(`Sum: ${sum}`);
return sum;
}
let t1 = performance.now();
addUsingReverseLoop(arr);
let t2 = performance.now();
console.log(`Time Taken ~ ${(t2 - t1)} milliseconds`)


// "Sum: 4999950000"
// "Time Taken ~ 46.199999982491136 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 44.96500000823289 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 43.880000011995435 milliseconds"

//反向 while 循环

let arr = [...Array(100000).keys()]
function addUsingReverseWhileLoop(ar){
var sum = 0;
var i = ar.length;
while (i--) {
sum += ar[i];
}
console.log(`Sum: ${sum}`);
return sum;
}
var t1 = performance.now();
addUsingReverseWhileLoop(arr);
var t2 = performance.now();
console.log(`Time Taken ~ ${(t2 - t1)} milliseconds`)


// "Sum: 4999950000"
// "Time Taken ~ 46.26999999163672 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 42.97000000951812 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 44.31500000646338 milliseconds"

//减少

let arr = [...Array(100000).keys()]
let t1 = performance.now();
sum = arr.reduce((pv, cv) => pv + cv, 0);
console.log(`Sum: ${sum}`)
let t2 = performance.now();
console.log(`Time Taken ~ ${(t2 - t1)} milliseconds`)


// "Sum: 4999950000"
// "Time Taken ~ 4.654999997001141 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 5.040000018198043 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 4.835000028833747 milliseconds"

//每人

let arr = [...Array(100000).keys()]
function addUsingForEach(ar){
let sum = 0;
ar.forEach(item => {
sum += item;
})
console.log(`Sum: ${sum}`);
return sum
}
let t1 = performance.now();
addUsingForEach(arr)
let t2 = performance.now();
console.log(`Time Taken ~ ${(t2 - t1)} milliseconds`)


// "Sum: 4999950000"
// "Time Taken ~ 5.315000016707927 milliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 5.869999993592501 mienter code herelliseconds"
// "Sum: 4999950000"
// "Time Taken ~ 5.405000003520399 milliseconds"

下面是一个 jsPerf,它对@Ankur 的答案进行了一些小的修改:

Https://jsben.ch/j6ywv

变化:

  1. 总结一个 [1,2,3,..,n][n,n-1,n-2,..,1]数组之间存在性能差异。

    (reversed array)标记的测试使用反向测试数组运行相同的 test-fn。

  2. console.log(`Sum: ${sum}`)对测量有负面影响并被移除(渲染输出需要时间)。

  3. 我为 reduceRight()增加了长凳。

enter image description here

为了获得更可靠的结果,您可能需要使用不同的数组多次运行每个测试,以获得平均运行时。

// Test functions
let fn_reduce = a => a.reduce((pv, cv) => pv + cv, 0);
let fn_reduceRight = a => a.reduceRight((pv, cv) => pv + cv, 0);
let tests = [fn_reduce, fn_reduceRight];


// Test config
let runs = 8;     // test runs
let length = 100000; // array length
// .. test with "array" and "reversed array"
let arr1 = Array.from({length}, (_, i) => i);
let arr2 = Array.from({length}, (_, i) => length - i - 1);


let out = [];
let outGrouped = {};
for(let i = 0; i < runs; i++){
tests.forEach(fn => {
(i % 2 ? [arr1, arr2] : [arr2, arr1]).forEach(arr => {
let isArrayReverse = arr !== arr1;
let sum = 0;
let t1 = performance.now();


sum = fn(arr);


let t2 = performance.now();
let duration = t2 - t1;
out.push({run: i, fn: fn.name, isArrayReverse, duration});


let group = `${fn.name}_${isArrayReverse}`;
outGrouped[group] ??= {fn: fn.name, isArrayReverse, duration: 0, runs: 0};
outGrouped[group].duration += duration;
outGrouped[group].runs++;
});
});
}


//console.log('out'); // detailed output


console.log('OPEN DEV-TOOLS for console.table()!');
console.log('Sort by "avg" column.');


console.table(Object.fromEntries(Array.from(Object.entries(outGrouped), ([group, {duration, runs, ...rest}]) => [group, {...rest, avg: duration / runs, duration, runs}])));

enter image description here