【算法与数据结构】Python遍历时删除元素问题总结

引言

在使用Python解决实际问题的时候,我们经常会遇到在遍历可迭代数据的时候,删除元素的场景。 这种操作是非常容易出错的,因为在对同一个可迭代对象, 同时进行遍历和删除的操作,如果处理不恰当,会导致代码得到错误的结果, 在这篇文章中,我们集中讨论一下这个问题。
背景案例, 删除一个list中所有为0 的元素:

lst = [1, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 2, 6]

for item in lst:
    if item == 0:
        lst.remove(item)
print lst

输出:(很明显答案是错误的)

[1, 1, 2, 8, 3, 2, 5, 0, 2, 6]

Python中常见的增删查操作

list

添加元素

  • append()
list1.append('c')
  • extend() – 列表元素添加到另一个列表
list1.extend(['a', 'b'])
  • insert()
list1.insert(1, 'x')
list3 = list1 + list2

删除元素

  • del
del list1[2]
del list1[-1]
del list1[2:3]
  • pop()
list1.pop()  # 删除最后一个元素
list1.pop(0)
  • remove() , 按照元素值删除, 删除匹配的第一个值。
list1.remove(2)
  • clear() # 清空
list1.clear()

复杂度分析:

insert(i, item) O(n)
append()  O(1)
pop(i) O(n)
in     O(n)
del    O(n)

dict

  • defaultdict, 不用担心key不存在
from collections import defaultdict
deep_dist = defaultdict(list)
  • 直接添加
dict1['key'] = value
  • update方法
xx = {'key': 'value'}
dict1.update(xx)
  • del
del dict1['key']
  • pop
dict1.pop('key')
  • clear
dict1.clear()
  • 判断某个key 是否在dict中
dict1.has_key('key')
if 'key' in dict2.keys()
if 'key' in dict1

复杂度分析
基于哈希算法,增删查的复杂度都为O(1)

set

  • add()
set1.add(1)
  • remove()
set1.remove(1)
  • discard
set1.discard(1)
  • 集合操作
a & b  # 交集
a | b  # 并
a - b  # 差
a ^ b  # 不同时在两个集合中

复杂度分析:
原理是哈希表, 增删查的复杂度是O(1)

如何遍历过程中删除元素

list

方案一:
采用for 循环倒序遍历的方式, 从列表末尾向前遍历, 这样删除元素时不会影响前面元素的索引。

my_list = [1, 2, 3, 4, 5]
to_delete = [3, 5]
for i in range(len(my_list) - 1, -1, -1):
    if my_list[i] in to_delete:
        del my_list[i]
print(my_list)

方案二:
遍历拷贝的list, 操作原始的list

for item in list1[:]:
    if item == 0:
        list1.remove(item)
print list1

方案三:
逆向思维,将希望保留的元素添加到一个新的列表中,就是想要的结果。

lis = [1,2,3,4]
new_lis = []
for i in lis:
    if i == 4:
        new_lis.append(i)
print(new_lis)

小结:
删除操作的时间复杂度应该是O(n), 个人还是比较喜欢方案一的实现方式, 这个方便实现更复杂的判断逻辑。

dict

方案一:
dict无法在迭代中删除元素, 可以把keys改为一个list, 然后遍历list 来删除dict的元素。

keys = list(d.keys())
for key in keys:
    if key == 'three':
        del d[key]

方案二:
可以直接创建出一个新的字典, 使用推导式。

m_dict = {'a': 1, 'b': 2}

new_dict = {key: value for key, value in my_dict.items() if key != 'a'}

返回的新字典就是删除之后的字典。

小结: 个人倾向于使用keys 列表化的方式删除字典元素, 相比较而言, 这样更节省空间。

set

在原set 上进行删除操作是会抛出异常的。
方案一: 可以使用copy()方法, 在原来的set上进行删除, 在新的set上进行遍历。 如下所示:

my_set = {1,2,3,4,5}
for i in my_set.copy():
    if i % 3 == 0:
        my_set.remove(i)
print(my_set)

小结:
思路是对两个set操作, 一个遍历,一个删除,相互不影响。

总结

本篇文章介绍了Python中list, dict 和set的遍历中删除元素的思路,处理类似的问题的时候,需要小心谨慎, 不然有可能很难定位出代码的bug。

参考资料

https://blog.csdn.net/weixin_36372610/article/details/113582573

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值