用JavaScript总结数组的最快方法是什么?快速搜索介绍了几种不同的方法,但如果可能的话,我想使用本机解决方案。这将在SpiderMonkey下运行。
我一直在想:
var count = 0;
for(var i = 0; i < array.length; i++)
{
count = count + array[i];
}
我敢肯定有比直接迭代更好的方法。
用JavaScript总结数组的最快方法是什么?快速搜索介绍了几种不同的方法,但如果可能的话,我想使用本机解决方案。这将在SpiderMonkey下运行。
我一直在想:
var count = 0;
for(var i = 0; i < array.length; i++)
{
count = count + array[i];
}
我敢肯定有比直接迭代更好的方法。
Answers:
reduce
是本机函数。在JS中面向性能的代码中,避免函数调用几乎总是更快,
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];
}
这等效于一会儿反向循环。它缓存该值并将其与0进行比较,从而加快了迭代速度。
有关更完整的比较列表,请参见我的JSFiddle。
注意: array.reduce在那里很可怕,但是在Firebug控制台中它是最快的。
我启动了一个 JSPerf进行数组求和。它是快速构建的,不能保证其完整性或准确性,但这就是编辑的目的:)
for
循环几乎相等。我进行了测试,有时增加的速度比减少的速度快。而且Array.reduce非常慢。jsperf.com/array-reduce-vs-foreach/2
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]; }
。这使它与其他缓存循环处于同一状况。
在寻找对数组求和的最佳方法时,我编写了一个性能测试。
在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.000ms
循环:255.000ms
减少:70.000ms
同时:214.000ms
parseInt
在reduce函数中需要一个a ?我尝试过,我的代码中也需要它。
根据此测试,最快的循环是反向的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方法...您可以轻松地使其成为一个辅助函数。
for(var i=0,n=a.length;i<n;i++){}
由于开始/停止控制结构,我更可能使用它。
arr
来从sum
方法?应该arr
真的this
吗?
基于此测试(for-vs-forEach-vs-reduce)和此(循环)
我可以这样说:
var total = 0;
for (var i = 0, n = array.length; i < n; ++i)
{
total += array[i];
}
对于您而言,您将不需要此功能,但是它增加了很多灵活性。
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 });
然后出现了forEach
,reduce
它们几乎具有相同的性能,并且随浏览器的不同而有所差异,但是它们的性能仍然最差。
我尝试使用performance.now()分析不同类型的循环的性能。我采用了一个非常大的数组,并发现了数组中所有元素的总和。我每次都运行代码三次,发现的forEach和减少是一个明显的赢家。
// For循环
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"
//做一会儿
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"
// forEach
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"
最简单,最快,更可重用和灵活的一种是:
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()
class UintArray extends Uint8Array { sum () { FUNCTION_CODE_HERE } }
两个末端相加怎么办?这样可以将时间缩短一半。像这样:
1、2、3、4、5、6、7、8;总和= 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()
。我认为这是一种更好的方法。你们有什么感想?
O(n/2)
等于O(n)
。为什么?因为您要估算的不是给定输入的速度,而是速度随着输入的变化而变化。如果将O(n)函数的输入加倍,则需要花费两倍的时间。如果将O(n / 2)函数的输入加倍,则需要花费两倍的时间。如果将输入倍增为O(n²),则需要四倍的时间。