I'm wondering if and what is a reliable and/or standard way of iterating an array whose length is changing inside the loop. I ask because I end up choosing a different method to do this each time I want to do it, e.g.
for ( var i = 0; i < myarray.length; i++ ) {
if (myarray[i] === 'something') {
myarray.splice(i, 1);
// *to avoid jumping over an element whose index was just shifted back to the current i
i--;
}
}
or
var i = 0;
while (myarray[i]) {
if (myarray[i] === 'something') {
myarray.splice(i, 1);
} else {
i++;
}
}
These are the ways I find myself doing this, but I'm curious if there is a standard approach.
I'm wondering if and what is a reliable and/or standard way of iterating an array whose length is changing inside the loop. I ask because I end up choosing a different method to do this each time I want to do it, e.g.
for ( var i = 0; i < myarray.length; i++ ) {
if (myarray[i] === 'something') {
myarray.splice(i, 1);
// *to avoid jumping over an element whose index was just shifted back to the current i
i--;
}
}
or
var i = 0;
while (myarray[i]) {
if (myarray[i] === 'something') {
myarray.splice(i, 1);
} else {
i++;
}
}
These are the ways I find myself doing this, but I'm curious if there is a standard approach.
Share Improve this question asked Jun 26, 2013 at 12:04 rob-gordonrob-gordon 1,4884 gold badges22 silver badges40 bronze badges 2 |2 Answers
Reset to default 23I find simpler to iterate in the other direction :
for (var i=myarray.length; i--; ) {
if (myarray[i] === 'something') myarray.splice(i, 1);
}
This way you don't have to change the increment when removing.
Many developers, especially the ones who didn't deal with C-like languages before JavaScript, find it confusing to deal with the subtleties of the decrement operator. The loop I wrote can also be written as
for (var i=myarray.length-1; i>=0; i--) {
However you choose to do it, starting in reverse and counting down is simplest. It also depends on whether your array is sparse and if you wish for it to remain sparse. Easiest is to create yourself a reusable function and your own library. You could do this. If you set compress
to true then your array will become a continuous rather than sparse array. This function will remove all matched occurrences of the value and will return an array of the removed elements.
Javascript
function is(x, y) {
if (x === y) {
if (x === 0) {
return 1 / x === 1 / y;
}
return true;
}
var x1 = x,
y1 = y;
return x !== x1 && y !== y1;
}
function removeMatching(array, value /*, compress (default = false)*/ ) {
var removed = [],
compress = arguments[2],
index,
temp,
length;
if (typeof compress !== "boolean") {
compress = false;
}
if (compress) {
temp = [];
length = array.length;
index = 0;
while (index < length) {
if (array.hasOwnProperty(index)) {
temp.push(array[index]);
}
index += 1;
}
} else {
temp = array;
}
index = 0;
length = temp.length;
while (index < length) {
if (temp.hasOwnProperty(index) && is(temp[index], value)) {
if (compress) {
removed.push(temp.splice(index, 1)[0]);
} else {
removed.push(temp[index]);
delete temp[index];
}
}
index += 1;
}
if (compress) {
array.length = 0;
index = 0;
length = temp.length;
while (index < length) {
if (temp.hasOwnProperty(index)) {
array.push(temp[index]);
}
index += 1;
}
}
return removed;
}
var test = [];
test[1] = 1;
test[50] = 2;
test[100] = NaN;
test[101] = NaN;
test[102] = NaN;
test[200] = null;
test[300] = undefined;
test[400] = Infinity;
test[450] = NaN;
test[500] = -Infinity;
test[1000] = 3;
console.log(test);
console.log(removeMatching(test, NaN));
console.log(test);
console.log(removeMatching(test, Infinity, true));
console.log(test);
Output
[1: 1, 50: 2, 100: NaN, 101: NaN, 102: NaN, 200: null, 300: undefined, 400: Infinity, 450: NaN, 500: -Infinity, 1000: 3]
[NaN, NaN, NaN, NaN]
[1: 1, 50: 2, 200: null, 300: undefined, 400: Infinity, 500: -Infinity, 1000: 3]
[Infinity]
[1, 2, null, undefined, -Infinity, 3]
On jsfiddle
i
directly in the.splice()
call:myarray.splice(i--, 1);
– user2437417 Commented Jun 26, 2013 at 12:16