社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python遍历列表时删除元素

青衣十三楼飞花堂 • 2 年前 • 293 次点击  
作者: wzhvictor
创建: 2016-10-19

tk在科学养猪群里问bluerust、scz是否碰上过这个Python坑,示例1

bas = [ 'ba1''ba2''ba3''ba4''ba5' ]
for ba in bas :
    print( ba )
    if ( ba.find( 'ba' ) != -1 ) :
        bas.remove( ba )
        print( bas )

print( bas )

即遍历list的过程中动态删除元素。上述代码输出如下

ba1
['ba2''ba3''ba4''ba5']
ba3                             // ba2被跳过去了
['ba2''ba4''ba5']
ba5                             // ba4被跳过去了
['ba2''ba4']
['ba2''ba4']                  // 列表未删干净

然后tk搜了个链接

https://segmentfault.com/a/1190000007214571

这篇讲得清楚,建议直接看原文,作者是wzhvictor。

对示例1做点改动,示例2

bas = [ 'ba1''ba2''ba3''ba4''ba5' ]
for  i in range( len( bas ) ) :
    print( i )
    print( bas[i] )
    if ( bas[i].find( 'ba' ) != -1 ) :
        del bas[i]
        print( bas )

print( bas )

上述代码输出如下

0
ba1
['ba2''ba3''ba4''ba5']
1
ba3
['ba2''ba4''ba5']
2
ba5
['ba2''ba4']
3
Traceback (most recent call last):
  File "", line 3in <module>
IndexError: list index out of range
['ba2''ba4']

循环变量i只递增到3,进而抛出IndexError。

该坑的起因是,for循环中i的取值从最开始就固定了,实际上要求list在for循环中保持不变;遍历list的过程中动态删除元素,导致list发生变化,而i仍固执地按原计划递增遍历list,于是漏删元素、索引越界。

对此,wzhvictor给了5种解决方案。

方式1,利用filter函数

bas = [ 'ba1''ba2''ba3''ba4''ba5''tk' ]
bas = list( filter( lambda ba:ba.find( 'ba' ) == -1, bas ) )
print( bas )

方法2,重新构造list

bas = [ 'ba1''ba2''ba3''ba4''ba5''tk' ]
bas = [ba for ba in bas if ba.find( 'ba' ) == -1]
print( bas )

方法3,遍历list的拷贝,对原始list进行删除操作

bas = [ 'ba1''ba2''ba3''ba4''ba5''tk' ]
for ba in bas[:] :
    if ( ba.find( 'ba' ) != -1 ) :
        bas.remove( ba )

print( bas )

方法4

bas = [ 'ba''ba''ba''ba''ba''tk' ]
while 'ba' in bas :
    bas.remove( 'ba' )

print( bas )

方法5,倒序遍历

bas = [ 'ba1''ba2''ba3''ba4''ba5''tk' ]
for i in range( len( bas )-1-1-1 ) :
    if ( bas[i].find( 'ba' ) != -1 ) :
        del bas[i]

print( bas )

就tk的示例1而言,方法4其实不适用,方法4适合从list中删除所有特定值。

这个坑我没踩过,用过方法2、3、4或者它们的变种。没像wzhvictor那样细究过for循环中i取值从最开始就固定,但我本能地对循环中动态处理的对象不放心,又懒得看Python文档,所以要么重新构造list,要么复制list再操作,完美避坑。今日看了wzhvictor的文章,方法1没用过,方法5没想过,方法5比较骚包,我第一次见。

Python表面上的不确定性真多,也没啥大不了,我的经验是,能用简明直观确定性的写法,就不要骚包玩花活,性能优化是后话。再就是,单元测试,无需再多强调。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/146809
 
293 次点击