python中对列表进行修改时的问题

python3的内置数据结构很多,列表怕是大家用的最多的结构了,有时候需要直接在列表本身进行修改(原列表的删除插入),写代码时会出现这么一个问题:

a = [0,1,1,2,2,3]
for i in a:
    if i == 1:
        a.remove(i)
print(a)

很简单的一段代码,就是将列表a中的1去掉,但是程序运行后输出的a是[0,1,2,2,3],并没有达到预期的效果,在网上看有人说是remove函数的问题(一脸懵逼,remove表示不背锅),其实不光是remove,涉及到for循环中任何对列表长度进行改变的情况,都有可能出现该类问题(比如pop和del)。
利用for..in…这一结构是按照索引进行操作的,当改变列表的结构后,用于操作的索引值不会发生改变,如上述例子:
第一次取值,i 得到 0,此时列表不变。
第二次取值,i得到 1,此时满足if条件,会从列表中删除第一个1,即之后的列表变为[0,1,2,2,3],值得注意的是,尽管列表缩短了,但是我在进行迭代时的索引是继续会进行++操作的。
第三次取值,i得到的并不是第二个1,而是第一个2,说的绕口一点就是,它会按照当前列表的过去索引进行取值。
第四次取值。。。
第五次取值。。。
这样一来便不会得到想要的结果,当并不是要求严格时,开一个新的列表比较容易解决这个问题,比如遇到符合条件的就append下,或者利用列表表达式就比较简单粗暴

a = [i for i in a if i != 1]

其实归根到底python还是不想让你在对原来列表进行修改时采取for…in…这个模式,因为不知觉的你就掉坑了,因此如果要修改,请用while,如果非得用remove,那么就得用copy模块产生一个副本辅助进行。如下:

a = [0,1,1,2,2,3]
i = 0
while i < len(a):
    if a[i] == 1:
        a.remove(a[i])
    else:
        i += 1

如果说for…in…是自动遍历可迭代对象,那while就是纯人工手动,这样可以保证在该加的时候让i进行++操作,不该的时候就不乱加。
如果对于for…in…的执念很深,就需要借助副本来做,copy模块中的深浅拷贝可以说是在面试中always被提到的,这里简单提一下他们与传统赋值(诸如b=a)的区别:
赋值是对对象的引用进行了复制,原对象没有变化,b=a后两个引用指向同一对象,因此原来要改变的时候两个全变。
浅拷贝和深拷贝是对对象进行复制,重新开出一块内存空间,浅拷贝会复制对象,但是对象内部如果存在子对象(拿列表来说,就是列表中还含有列表,例[1,2,3,4,[5,6,7]]),则不会复制,而是直接引用原对象的。深拷贝则是全部进行拷贝。
从定义上来看,深拷贝与浅拷贝都可以用于对该题目的解决。如下:

import copy
a = [0,1,1,2,2,3]
aa = copy.copy(a)
for i in a:
    if i == 1:
        aa.remove(i)

当然,deepcopy也可以。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值