Python陷阱--数组-循环删除

Python陷阱–数组-循环删除

1. 前言

今天去面试了,问到数组的循环删除问题,算是Python需要注意的地方之一吧。一起回顾一下吧。

问题如下:

取 li = [1, 2, 3, 4, 5, 6],运行如下代码后结果如何:

#问题一
li = [1, 2, 3, 4, 5, 6]
for i in range(len(li)):
    if li[i] = 2:
        li.pop(i)

print(li)

#问题二
li = [1, 2, 3, 4, 5, 6]
for i in li:
    li.remove(i)
    
print(i)

1.1 简单介绍

相信大家都对答案并不陌生,这里为初学不久的萌新们(比如本山人)简单分析一下。

问题一中的代码会报错,原因是删除元素2后,列表的长度会减小(6 -> 5)但是遍历的区间不会变range(6)所以会导致索引超出范围,IndexError

问题二中的列表无法被清空,原因是删除时列表内容的变动,如下所示:

[外链图片转存失败(img-SNRhek22-1564140390092)(images\1564138751862.png)]


2. 解决方案

关于问题二解决方案如下:

2.1 蠢办法

该方法仅用于提供思路,分析问题,如果时间紧张请参考2.2,挤出来的时间可以多陪陪女朋友(可拉倒吧,认真看)。

经分析:问题二的错误之处在于遍历删除元素的同时导致列表内容发生变化,从而每次循环开始,指针移动时会“漏掉”元素,所以解决问题的办法在于保证遍历的过程中,指针将要指到的部分列表内容不会变化。

上解决方案:

#蠢办法,建立副本
li = [1, 2, 3, 4, 5, 6]
li_copy = li.copy()  #浅拷贝 li[:]也可
for i in li_copy:
    li.remove(i)
    
print(i)
  • 从内存空间分析 ,增加了消耗,不好。

2.2 巧办法

经2.1分析得,只需保证遍历的过程中,指针将要指到的部分列表内容不会变化即可。结合每个遍历过程开始时,指针只会后移。巧用反向遍历,解决问题。

li = [1, 2, 3, 4, 5, 6]
for i in li[::-1]:
    li.remove(i)

关于li[::-1]是否会造成额外开销问题:

In [1]: l = [257,2,3,4,5,6]                                                                    

In [2]: print(id(l[0]))                                                                      
140307042424592

In [3]: for i in l[::-1]: 
   ...:         print(i, id(i)) 
   ...:                                                                                      
6 10919488
5 10919456
4 10919424
3 10919392
2 10919360
1 140307042424592

In [4]: print(id(l))                                                                         
140218462889544
In [5]: print(id(l[::-1]))                                                                   
140218464334344
  • 答案是,反向迭代不会产生额外开销,反向迭代l[::-1]并非是l的副本。
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值