for 使用,谨防此问题

 for 使用注意

for 语句遍历容器类型或可迭代类型时,如果涉及到增加、删除元素,就需要小心。比如请先看下面的例子:

删除列表中的某个元素值,可能有重复,要求元素顺序不变,空间复杂度为O(1),如果像下面这样写就会有问题:

def delItems(nums, target):
    for item in nums:
        if item == target:
            nums.remove(item)
    return nums

对于大多数情况,上面的代码无法暴露出bug。但是考虑下面输入(特点:被删除的值连续出现):

r = delItems([2, 1, 3, 1, 1, 3], 1)
print(r)

打印结果为:[2,3,1,3]

对于刚接触编程的朋友对此很不解,为什么其中一个1未被remove.

不管是Python, Java, C++,列表或数组删除元素时,其后面的元素都会逐次前移1位,但是for依然会正常迭代,因此“成功”规避了相邻的后面元素1.

图形解释命中目标后的一些列动作:

上面的列表
命中目标
删除元素1

下步最关键:解释器自动前移删除位置后的所有元素

但是,等到下一次迭代时,迭代器不等待,正常移动到下一个位置:

这样元素3成功逃避是否与目标值相等的检查。

结论:命中目标处的后一个位置都逃避了是否与目标值相等的检查,所以一旦有连续目标值,必然就会漏掉,进而触发上面的bug.

明白上面这个原因后,重新再改写一遍删除所有重复元素的代码,下面代码不再使用for直接遍历元素(再说一遍:增删元素原来迭代器发生改变,所以会导致异常行为),而是使用索引访问:

def delItems(nums, target):
    i = 0
    while i < len(nums):
        if nums[i] == target:
            del nums[i]
            i -= 1
        i += 1
    return nums

r = delItems([2, 1, 3, 1, 1, 3], 1)
print(r) # [2,3,3]

如果元素等于target,从数组nums中删除nums[i],删除后解释器自动将i后的元素都前移1位。据此,巧妙的控制i值,一旦命中立即i减去1,这样确保不漏检查。

《end》

送畅销书籍 Python网络爬虫 2本

送书方法:近一周分享最多的前2名,自动获得上面书籍。请于1天内联系小编(详情Python小例子公众号界面-点击联系我按钮,获得小编微信)。

如果想了解和购买这本书,可点击下面链接,现在当当有每满100减50的活动:

接下来持续会有送书,欢迎大家积极参与公众号的文章分享原创不易,欢迎三连支持:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值