Mig*_* G. 12 javascript arrays performance
我正在尝试这个Codewars挑战,问题涉及找到一个数的除数,然后计算这些除数的平方和.我找到了解决这个问题的两种方法.
第一种方法是基于另一个关于找到所有除数之和的Stackoverflow问题,并且最初看起来很聪明:
function divisorsSquared(n) {
// create a numeric sequence and then reduce it
return [...Array(n+1).keys()].slice(1)
.reduce((sum, num)=>sum+(!(n % (num)) && Math.pow(num,2)), 0);
}
Run Code Online (Sandbox Code Playgroud)
我使用的第二种方法是使用简单的for循环:
function divisorsSquared(n) {
var sum = 0;
for(var i = 1; i<= n; i++){
if(n % i === 0) sum += Math.pow(i,2);
}
return sum;
}
Run Code Online (Sandbox Code Playgroud)
现在我注意到第一种方法明显慢于第二种方法,快速jsperf测试证实了这一点.
我的问题是:为什么第一种方法如此慢,哪种方法在生产代码中更可取?
在Codewars上我注意到,对于许多挑战,使用类似的数组方法有一些聪明的单行解决方案.作为一个初学者,即使性能更差,这些解决方案可能被认为是比for循环更好的做法吗?
Array(n+1)分配一个带有n + 1个元素的数组,Array(n+1).keys()在创建的数组的索引上返回一个迭代器,但是扩展运算符[...Iterator]帮助将这个迭代器"解包"到另一个数组中,然后最终slice(1)复制第二个创建的数组,从索引开始1分配另一个数组数组(第三个)0丢弃的数字.所以这是3个分配,但有2个被分配.您for-loop不分配任何阵列,它是在O(n)的一个简单穿越只有2拨款i和sum,所以它是更有效的sum+(!(n % (num)) && Math.pow(num,2))本质上是相同的,if(n % i === 0) sum += Math.pow(i,2);但if方法更具可读性.如果我是法官,我会选择第二种方法,因为它更有效,但它更有利于可读性.查看代码,for 循环显然不那么复杂且更具可读性。
考虑到您在一个团队中工作,您的最大数量的团队成员将立即知道代码在做什么。有些人将不得不查找reduce()方法是什么,但他们也会知道发生了什么。所以在这里,for 循环更容易让其他人阅读和理解。
另一方面,本机数组函数(filter(), map(), reduce())将使您免于编写一些额外的代码,并且性能也会变慢。
对于初学者,我认为 for 循环应该比原生数组函数更好。
功能或命令式方法在JS中有所作为。当务之急总是赢。然而,现实是,大多数时候,更好的算法才是赢家。您的代码是一种幼稚的方法。您可以通过检查整数直到目标值的平方根来调整它的性能,以更好地工作,每次检查将得到两个答案。如果目标是100,如果2是股息,那么100/2也必须也是股息。因此公平地检查Math.sqrt(100) - 1并小心处理10以免再次考虑是公平的。
因此,现在具有减少功能的解决方案击败了命令天真的解决方案。
function divisorsSquared(n) {
var sn = Math.sqrt(n);
return Array.from({length:~~sn-1},(_,i) => i+1)
.reduce((s,m) => n%m ? s : s + m*m + (n/m)*(n/m), 0) + (n%sn ? 0 : sn*sn);
}
var result = 0;
console.time("functional and tuned");
result = divisorsSquared(1000000);
console.timeEnd("functional and tuned");
console.log("for input: 1000000 the result is:",result);
function dvssqr(n) {
var sum = 0;
for(var i = 1; i<= n; i++){
if(n % i === 0) sum += Math.pow(i,2);
}
return sum;
}
console.time("imperative and naive");
result = dvssqr(1000000);
console.timeEnd("imperative and naive");
console.log("for input: 1000000 the result is:",result);Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5006 次 |
| 最近记录: |