Javascript 拼接方法中的奇怪错误
Weird bug in Javascript splice method
我有一个包含 "Zeros" 的数组,我想移动所有
"Zeros" 到数组的最后一个索引。
预期输出为:
[1,2,3,0,0,0,0]
但我得到的是:
[1,2,0,3,0,0,0]
let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;
for (i = 0; i < len; i++) {
if (a[i] == 0) {
count = count + 1;
a.splice(i, 1);
}
}
for (j = 0; j < count; j++) {
a.push(0);
}
console.log(a);
当您从数组中删除项目时,所有元素都会向下移动一位。当您推进索引 (i++) 时,您会跳过数组中向下移动的项目,该项目恰好是数组中的连续零。
解决方法:向后执行for next循环,就可以了。
您可以在每次使用 splice 时添加 i--;
和 len--;
:
let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;
for (i = 0; i < len; i++) {
if (a[i] == 0) {
count = count + 1;
a.splice(i, 1);
i--; len--;
}
}
for (j = 0; j < count; j++) {
a.push(0);
}
console.log(a);
这是因为当你拼接1个元素时,数组的key被下移了一位,所以你要检查的下一个元素的key和你刚刚移除的元素的key是一样的。 len 也用 len--;
更正,因为我们刚刚删除了一个元素。
虽然此答案是使用您的原始计划执行此操作的正确方法,但它是一种修复方法。您的问题是您遍历了一个数组,并且该数组在循环过程中丢失了元素,通常在这些情况下正确的方法是向后循环。这样,在循环期间可能会更改密钥的元素就是我们已经检查过的元素。
您可以使用 Array.prototype.sort()
来更简单:
const array = [0, 1, 2, 0, 0, 3, 0];
const sortedArray = array.sort((a, b) => {
if (a === 0) {
return 1;
}
if (b === 0) {
return -1;
}
return a - b;
});
console.log(sortedArray);
因为splice会改变数组的长度,所以可以从数组的末尾开始迭代,将找到的值直接拼接到最后一个索引。
使用这种方法,您只需要一个循环。
var a = [0, 1, 2, 0, 0, 3, 0],
i = a.length;
while (i--) {
if (a[i] === 0) {
a.splice(a.length, 0, ...a.splice(i, 1));
}
}
console.log(a);
没有拼接的更短的方法 - 从零开始。
var a = [0, 1, 2, 0, 0, 3, 0],
i, j = 0;
for (i = 0; i < a.length; i++) {
if (a[i] !== 0) {
[a[j], a[i]] = [a[i], a[j]]; // swap
j++;
}
}
console.log(a);
在for循环中拼接数组时,数组和它的长度都会改变。
为此,您必须通过减去 1
来修复 for 循环中的 i
i++;
并通过减去 1 或重新获取长度来固定长度
let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;
for (i = 0; i < len; i++) {
if (a[i] == 0) {
count = count + 1;
a.splice(i, 1);
len = a.length;
i--;
}
}
for (j = 0; j < count; j++) {
a.push(0);
}
console.log(a);
请注意,每个 对 splice
的调用通常有 O(n) complexity。有许多方法可以通过单个 O(n) 迭代更有效地实现您想要的结果一个数量级。这是一个:
let a = [0, 1, 2, 0, 0, 3, 0]
for (let i=0, j=0; j<a.length; j++)
if (a[j] && i != j)
[a[i++], a[j]] = [a[j], 0]
console.log(a)
与其一遍又一遍地拼接数组,不如换一种方法:
let a = [0, 1, 2, 0, 0, 3, 0];
// create some more (random) data
for (let i = a.length; i < 30; ++i)
a[i] = Math.floor(Math.random() * Math.random() * 10);
console.log(""+a);
let i = 0, j = 0, len = a.length;
// move non-0 values to the front
while (i < len) {
if (a[i] !== 0) {
a[j++] = a[i];
}
++i;
}
// fill the end of the list with 0
while (j < len) a[j++] = 0;
console.log(""+a);
我有一个包含 "Zeros" 的数组,我想移动所有 "Zeros" 到数组的最后一个索引。
预期输出为:
[1,2,3,0,0,0,0]
但我得到的是:
[1,2,0,3,0,0,0]
let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;
for (i = 0; i < len; i++) {
if (a[i] == 0) {
count = count + 1;
a.splice(i, 1);
}
}
for (j = 0; j < count; j++) {
a.push(0);
}
console.log(a);
当您从数组中删除项目时,所有元素都会向下移动一位。当您推进索引 (i++) 时,您会跳过数组中向下移动的项目,该项目恰好是数组中的连续零。
解决方法:向后执行for next循环,就可以了。
您可以在每次使用 splice 时添加 i--;
和 len--;
:
let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;
for (i = 0; i < len; i++) {
if (a[i] == 0) {
count = count + 1;
a.splice(i, 1);
i--; len--;
}
}
for (j = 0; j < count; j++) {
a.push(0);
}
console.log(a);
这是因为当你拼接1个元素时,数组的key被下移了一位,所以你要检查的下一个元素的key和你刚刚移除的元素的key是一样的。 len 也用 len--;
更正,因为我们刚刚删除了一个元素。
虽然此答案是使用您的原始计划执行此操作的正确方法,但它是一种修复方法。您的问题是您遍历了一个数组,并且该数组在循环过程中丢失了元素,通常在这些情况下正确的方法是向后循环。这样,在循环期间可能会更改密钥的元素就是我们已经检查过的元素。
您可以使用 Array.prototype.sort()
来更简单:
const array = [0, 1, 2, 0, 0, 3, 0];
const sortedArray = array.sort((a, b) => {
if (a === 0) {
return 1;
}
if (b === 0) {
return -1;
}
return a - b;
});
console.log(sortedArray);
因为splice会改变数组的长度,所以可以从数组的末尾开始迭代,将找到的值直接拼接到最后一个索引。
使用这种方法,您只需要一个循环。
var a = [0, 1, 2, 0, 0, 3, 0],
i = a.length;
while (i--) {
if (a[i] === 0) {
a.splice(a.length, 0, ...a.splice(i, 1));
}
}
console.log(a);
没有拼接的更短的方法 - 从零开始。
var a = [0, 1, 2, 0, 0, 3, 0],
i, j = 0;
for (i = 0; i < a.length; i++) {
if (a[i] !== 0) {
[a[j], a[i]] = [a[i], a[j]]; // swap
j++;
}
}
console.log(a);
在for循环中拼接数组时,数组和它的长度都会改变。
为此,您必须通过减去 1
来修复 for 循环中的 i i++;
并通过减去 1 或重新获取长度来固定长度
let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;
for (i = 0; i < len; i++) {
if (a[i] == 0) {
count = count + 1;
a.splice(i, 1);
len = a.length;
i--;
}
}
for (j = 0; j < count; j++) {
a.push(0);
}
console.log(a);
请注意,每个 对 splice
的调用通常有 O(n) complexity。有许多方法可以通过单个 O(n) 迭代更有效地实现您想要的结果一个数量级。这是一个:
let a = [0, 1, 2, 0, 0, 3, 0]
for (let i=0, j=0; j<a.length; j++)
if (a[j] && i != j)
[a[i++], a[j]] = [a[j], 0]
console.log(a)
与其一遍又一遍地拼接数组,不如换一种方法:
let a = [0, 1, 2, 0, 0, 3, 0];
// create some more (random) data
for (let i = a.length; i < 30; ++i)
a[i] = Math.floor(Math.random() * Math.random() * 10);
console.log(""+a);
let i = 0, j = 0, len = a.length;
// move non-0 values to the front
while (i < len) {
if (a[i] !== 0) {
a[j++] = a[i];
}
++i;
}
// fill the end of the list with 0
while (j < len) a[j++] = 0;
console.log(""+a);