当需要对一个集合遍历删除元素的时候,都应该倒着删
这个也是我在实际写东西的时候,发现的一个比较有意义的经验。我对比了jsvascript和C#,发现“当需要对一个集合遍历删除元素的时候,都应该倒着删”这句话实在是一般无二。
int nowRemoveIndex = combination.Count() - 1; while (true) { if (combination.Count() > lastCombitionCount) combination.RemoveAt(nowRemoveIndex); else break; nowRemoveIndex--; }
上面这小段代码,是C#的,其中combination表示的是一个List集合。
这段代码的场景指的是,我目前有一个好几层的递归,每一层都会往这个集合插入数据,但是当递归在回归的时候,我发现这不是我要的数据,于是我就要把他从尾部添加上去的数据删掉。
这个很轻易的就可以想到,这个肯定就是从后往前遍历,然后逐个删除。
接下来再看一段JavaScript代码:
let machineId = app.globalData.machineId for (let i = cartCache.length - 1; i >= 0; i--) { if (cartCache[i].MachineID === machineId) { cartCache.splice(i, 1) console.log('已清理一条缓存:') console.log(cartCache[i]) } }
这是小程序中的一段js代码。
当时的代码场景是,假设我目前有好几个购物车,machineId可以看成是分类id,一个分类对应一个购物车(业务场景是虚构的,请不要较真)。但是,我的购物车数据是全部丢到一个集合里面,即上面的cartCache。那现在我要清空其中一个购物车,这个时候就是必须得遍历cartCache,然后用machineId这个标识来找到我要清除的对象。
这里可以看到,我是从后往前遍历,然后才使用splice删除元素的。
现在来做个实验,正着删和倒着删的结果会不会不一样
let testArray1 = [1,3,4,5,2,7] let testArray2 = [1,3,4,5,2,7] for (let i = 0; i < testArray1.length; i++) { if(testArray1[i] >= 4) testArray1.splice(i,1) } for (let i = testArray2.length - 1; i >= 0; i--) { if(testArray2[i] >= 4) testArray2.splice(i,1) } console.log('testArray1的结果为:') console.log(testArray1) console.log('testArray2的结果为:') console.log(testArray2)
上面还是两个普通的js for循环遍历数组然后删除元素,不同的是,一个是正着删,还一个则是倒着删,其结果如下:
现在思考的时候来了,为什么正着删会多出一个5没删掉呢?
这个是因为,当循环遍历到4的时候,此时 i 的值等于2,在执行完splice的之后,4这个元素被删除了,而 i 顺利成章的 ++,然后变成了 3,而此时索引 3 对应的元素是 2 ,因为4被删除了,所以5变成了刚刚4的位置,正好就这么把5给漏了。
以上是用JavaScript做的演示,关于其他语言,可以自己多尝试。对于C#,如果正着删的话,代码运行的时候是会直接报错。