缺少数组中的最后一个元素
Missing last element in array
我正在尝试将所有质数相加得到一个数。
首先我删除了所有的偶数并将其余的推到一个奇数数组中。
然后我将遍历数组并拼接除 1 和它们本身以外的其他数字的所有数字,并将它们替换为零。
一切似乎都很顺利,但是,请注意我的第一个 console.log 最后一个元素是 977(这是传递的数字)。
一行之后,我 forEach 数组并打印所有超过 970 的数字,但 977 不存在:/
关于这是怎么发生的有什么想法吗? (我排除了巫术..)
function sumPrimes(num) {
var arr = [2];
for (var i = 3; i <= num; i++) {
if (i % 2 !== 0) {
arr.push(i);
}
}
console.log(arr);
arr.forEach(function(x) {
if(x > 970){
console.log(x);
}
if (x > 3) {
for (var j = 3; j < x; j += 2) {
if (x % j == 0) {
arr.splice(arr.indexOf(x), 1, 0);
}
}
}
})
// console.log(arr);
var res = arr.reduce(function(acc, val) {
return acc + val;
}, 0)
console.log(res);
}
sumPrimes(977);
问题在于您如何操作数组,而数组实际上永远不会包含 977。
发生的事情是您找到一个非素数并更改数组,使其现在为 0,但您继续 运行 检查该素数。
这会导致该值的任何后续 indexOf 查找为 return -1,因此您会得到意想不到的结果。
if (x % j == 0) {
arr.splice(arr.indexOf(x), 1, 0); // This won't work after the first assign to 0
}
您可以通过在拼接后立即插入一个 'break;' 来使环路短路来轻松解决此问题,但是您可以使用 forEach 中可用的索引参数轻松简化并显着加快此操作完全删除数组位置查找。
function sumPrimes(num) {
var arr = [2];
for (var i = 3; i <= num; i++) {
if (i % 2 !== 0) {
arr.push(i);
}
}
console.log(arr);
arr.forEach(function(x, idx) {
if(x > 970){
console.log(x);
}
if (x > 3) {
for (var j = 3; j < x; j += 2) {
if (x % j == 0) {
arr[idx] = 0;
break;
}
}
}
})
// console.log(arr);
var res = arr.reduce(function(acc, val) {
return acc + val;
}, 0)
console.log(res);
}
sumPrimes(977);
编辑:如果有人想要一种简单、更有效的方法来确定一个数是否为质数,我建议使用 Trial Division 方法,而不是上面的方法。
您可以在 Rosetta code:
上找到一个简洁、经过良好测试的示例
function isPrime(n) {
if (n == 2 || n == 3 || n == 5 || n == 7) {
return true;
} else if ((n < 2) || (n % 2 == 0)) {
return false;
} else {
for (var i = 3; i <= Math.sqrt(n); i += 2) {
if (n % i == 0)
return false;
}
return true;
}
}
console.log(isPrime(977));
正如@Dave L 也发现的那样,问题似乎与此有关:
if (x > 3) {
for (var j = 3; j < x; j += 2) {
if (x % j == 0) {
arr.splice(arr.indexOf(x), 1, 0);
}
}
}
}
当我注释掉它时,977 被打印出来了,但是有了它,我不得不尝试使用 979 让它打印 977。你可能从未怀疑过它的原因是因为 JavaScript 是异步的,所以这实际上是在 之前 日志语句执行的!
Dave 的答案是正确的,但为了这个练习,另一个循环解决方案
function sumPrimes(num) {
var prime = [2];
var isPrime;
for (var i = 3; i <= num; i++) {
if (i % 2 !== 0) {
isPrime = true;
prime.forEach(function (v) {
isPrime = isPrime && i % v != 0;
});
if (isPrime) {
prime.push(i);
}
}
}
console.log(prime);
var res = prime.reduce(function (acc, val) {
return acc + val;
}, 0)
console.log(res);
}
sumPrimes(977);
当您使用 array.reduce 时,为什么不也使用 array.map 为您的数组播种初始值(而不是使用 for 循环)?
function seedArray(start, end) {
return Array.apply(null, new Array(end - start + 1)).map(
function(x, i) {
return i + start;
}
);
}
当然你可以做一些错误检查以确保 p1 和 p2 是非负整数,p2 >= p1 以确保 new Array() 不会崩溃。
我正在尝试将所有质数相加得到一个数。
首先我删除了所有的偶数并将其余的推到一个奇数数组中。
然后我将遍历数组并拼接除 1 和它们本身以外的其他数字的所有数字,并将它们替换为零。
一切似乎都很顺利,但是,请注意我的第一个 console.log 最后一个元素是 977(这是传递的数字)。
一行之后,我 forEach 数组并打印所有超过 970 的数字,但 977 不存在:/
关于这是怎么发生的有什么想法吗? (我排除了巫术..)
function sumPrimes(num) {
var arr = [2];
for (var i = 3; i <= num; i++) {
if (i % 2 !== 0) {
arr.push(i);
}
}
console.log(arr);
arr.forEach(function(x) {
if(x > 970){
console.log(x);
}
if (x > 3) {
for (var j = 3; j < x; j += 2) {
if (x % j == 0) {
arr.splice(arr.indexOf(x), 1, 0);
}
}
}
})
// console.log(arr);
var res = arr.reduce(function(acc, val) {
return acc + val;
}, 0)
console.log(res);
}
sumPrimes(977);
问题在于您如何操作数组,而数组实际上永远不会包含 977。
发生的事情是您找到一个非素数并更改数组,使其现在为 0,但您继续 运行 检查该素数。
这会导致该值的任何后续 indexOf 查找为 return -1,因此您会得到意想不到的结果。
if (x % j == 0) {
arr.splice(arr.indexOf(x), 1, 0); // This won't work after the first assign to 0
}
您可以通过在拼接后立即插入一个 'break;' 来使环路短路来轻松解决此问题,但是您可以使用 forEach 中可用的索引参数轻松简化并显着加快此操作完全删除数组位置查找。
function sumPrimes(num) {
var arr = [2];
for (var i = 3; i <= num; i++) {
if (i % 2 !== 0) {
arr.push(i);
}
}
console.log(arr);
arr.forEach(function(x, idx) {
if(x > 970){
console.log(x);
}
if (x > 3) {
for (var j = 3; j < x; j += 2) {
if (x % j == 0) {
arr[idx] = 0;
break;
}
}
}
})
// console.log(arr);
var res = arr.reduce(function(acc, val) {
return acc + val;
}, 0)
console.log(res);
}
sumPrimes(977);
编辑:如果有人想要一种简单、更有效的方法来确定一个数是否为质数,我建议使用 Trial Division 方法,而不是上面的方法。
您可以在 Rosetta code:
上找到一个简洁、经过良好测试的示例function isPrime(n) {
if (n == 2 || n == 3 || n == 5 || n == 7) {
return true;
} else if ((n < 2) || (n % 2 == 0)) {
return false;
} else {
for (var i = 3; i <= Math.sqrt(n); i += 2) {
if (n % i == 0)
return false;
}
return true;
}
}
console.log(isPrime(977));
正如@Dave L 也发现的那样,问题似乎与此有关:
if (x > 3) {
for (var j = 3; j < x; j += 2) {
if (x % j == 0) {
arr.splice(arr.indexOf(x), 1, 0);
}
}
}
}
当我注释掉它时,977 被打印出来了,但是有了它,我不得不尝试使用 979 让它打印 977。你可能从未怀疑过它的原因是因为 JavaScript 是异步的,所以这实际上是在 之前 日志语句执行的!
Dave 的答案是正确的,但为了这个练习,另一个循环解决方案
function sumPrimes(num) {
var prime = [2];
var isPrime;
for (var i = 3; i <= num; i++) {
if (i % 2 !== 0) {
isPrime = true;
prime.forEach(function (v) {
isPrime = isPrime && i % v != 0;
});
if (isPrime) {
prime.push(i);
}
}
}
console.log(prime);
var res = prime.reduce(function (acc, val) {
return acc + val;
}, 0)
console.log(res);
}
sumPrimes(977);
当您使用 array.reduce 时,为什么不也使用 array.map 为您的数组播种初始值(而不是使用 for 循环)?
function seedArray(start, end) {
return Array.apply(null, new Array(end - start + 1)).map(
function(x, i) {
return i + start;
}
);
}
当然你可以做一些错误检查以确保 p1 和 p2 是非负整数,p2 >= p1 以确保 new Array() 不会崩溃。