Python遍历list调用remove方法结果与条件相反问题排查
问题成因
该bug是遍历列表过程中原地修改列表导致的索引错位导致的,具体执行逻辑如下:
- 初始生成的
pair列表为[[1,3], [2,4], [3,5], [4,1], [5,2]],其中前三个元素都满足cost>gas的删除条件,后两个元素需要保留。 - Python的
for循环是按列表索引顺序依次取值的,遍历过程中如果删除当前元素,列表后续元素会整体向前移动一位,但循环的索引指针会继续向后走,不会回退检查被前移的元素:- 第一次循环取索引0的元素
[1,3],满足删除条件,执行remove后列表变为[[2,4], [3,5], [4,1], [5,2]],原本在索引1的[2,4]前移到了索引0位置 - 第二次循环直接取索引1的元素,也就是当前列表里的
[3,5],完全跳过了已经移到索引0的[2,4],[3,5]满足删除条件被移除,列表变为[[2,4], [4,1], [5,2]] - 第三次循环取索引2的元素
[5,2],不满足删除条件,循环直接结束
- 第一次循环取索引0的元素
- 本该被删除的
[2,4]因为索引错位被漏判,最终就得到了你看到的错误输出。
正确实现方式
有两种常用的无副作用实现方案:
- 方案1:遍历原列表的副本做判断,避免遍历过程受列表修改影响
def canCompleteCircuit(gas,cost): pair = [[a,b] for a,b in zip(gas,cost)] # 遍历pair的浅拷贝,遍历对象不会随原列表修改变化 for a in pair.copy(): if a[1] > a[0]: pair.remove(a) print(pair) gas = [1,2,3,4,5] cost = [3,4,5,1,2] canCompleteCircuit(gas,cost) # 输出:[[4, 1], [5, 2]],符合预期
- 方案2:直接用列表推导式生成过滤后的新列表(更推荐,代码简洁无索引问题,执行效率更高)
def canCompleteCircuit(gas,cost): # 生成列表时直接过滤掉cost>gas的元素,不需要后续删除操作 pair = [[a,b] for a,b in zip(gas,cost) if b <= a] print(pair) gas = [1,2,3,4,5] cost = [3,4,5,1,2] canCompleteCircuit(gas,cost) # 输出:[[4, 1], [5, 2]],符合预期
内容的提问来源于stack exchange,提问作者Achyut Jagini
相关产品推荐
相关产品推荐

