31-列表变动时索引递减
4.3.4 列表变动时索引递减
当在循环一个列表的同时还在修改它,情况就变得有趣了。因为当列表修改时,需要相应的修改循环终止条件。最好的情况是循环的结果不是你想要的;最糟糕的情况是这个循环永远不会结束。常见的做法是使用索引递减的循环方式,也就是循环顺序由终止的地方开始,到起始位置结束。这时,如果列表有增删操作,就不会影响循环终止条件。
比如,从 bigArrayOfNumbers 中删除所有质数。使用数组中的splice方法给数组添加或者删除一个元素(详情见第8章)。下面代码就不会达到预期的效果:
for(let i=0; i<bigArrayOfNumbers.length; i++) {
if(isPrime(bigArrayOfNumbers[i])) bigArrayOfNumbers.splice(i, 1);
}
因为索引是递增的,而程序执行中还在删除元素,所以循环的时候很可能跳过一些素数(如果它们是相邻的)。可以通过索引递减来解决这个问题:
for(let i=bigArrayOfNumbers.length-1; i >= 0; i--) {
if(isPrime(bigArrayOfNumbers[i])) bigArrayOfNumbers.splice(i, 1);
}
这里要小心循环的起始和判断条件:索引必须从比数组长度小一的位置开始,因为数组下标是从零开始的。同时,当i大于或等于0时继续循环;否则会漏掉第一个元素(如果第一个元素恰好是素数,结果就会出问题了)。