python - 遍历列表和删除元素的最佳方法是什么?我目前的做法会导致元素被跳过
问题描述
我正在使用这种方法,但是 for 循环跳过了元素。调试后知道为什么跳过了,所以想知道有没有更好的方法或者合适的方法。
这是我的代码:
class Birthday:
name = ''
date = ''
def __init__(self, name, date):
self.name = name
self.date = date
...
dt1 = datetime.datetime.utcfromtimestamp(1428916628.0) # Year: 2015
dt2 = datetime.datetime.utcfromtimestamp(1328916628.0) # Year: 2012
dt3 = datetime.datetime.utcfromtimestamp(1228916628.0) # Year: 2008
dt4 = datetime.datetime.utcfromtimestamp(1128916628.0) # Year: 2005
dt5 = datetime.datetime.utcfromtimestamp(1028916628.0) # Year: 2002
b1 = Birthday('John', dt1)
b2 = Birthday('Larry', dt2)
b3 = Birthday('David', dt3)
b4 = Birthday('Joe', dt4)
b5 = Birthday('Jerry', dt5)
# Elements are mixed on purpose
dt_list = [b3, b1, b5, b4, b2]
# Sort the order of elements by date
dt_list.sort(key=lambda y: y.date)
for x in dt_list:
dt_list.remove(x)
if len(dt_list) <= 3:
break
Expected: 2008, 2012, 2015
Result: 2005, 2012, 2015
我正在考虑将其添加到 for 循环的第一个换行符:
x = dt_list[0]
但是感觉不太对。
解决方案
迭代期间的变异是不好的
首先,对您正在迭代的列表进行变异很少是一个好主意。特别是,这是您当前问题的根源。让我们看一个类似的例子。
l = [1, 2, 3, 4]
for x in l:
l.remove(x)
print(l) # [2, 4]
遍历一个列表将返回l[0]
, l[1]
, l[2]
... 等等,直到它到达列表的末尾。特别是,这意味着如果索引更改,您可能会跳过一些元素。这就是这里发生的事情。
如果你想改变你的列表,你应该这样做。
l = [1, 2, 3, 4, 5]
del l[:-3]
print(l) # [3, 4, 5]
虽然,变异数据并不比创建新列表更省时。当您从列表中删除一个元素时,下一个元素需要向左移动,这很昂贵。上面的操作是O(n),其中n是列表的长度。
在这种情况下,创建一个新列表实际上效率更高。
切片
对列表进行切片会返回一个新列表,并且是O(k),其中k是切片的大小。因此,恢复最后三个元素实际上是在恒定时间内运行的。
l = [1, 2, 3, 4, 5]
new_l = l[-3:]
print(new_l) # [3, 4, 5]
此外,由于该list.__getitem__
函数是用 C 编写的,因此与 for 循环相比,它的速度非常快。
这是只获取最后三个元素的最快方法。
推荐阅读
- freeradius - 使用我们自己的 2FA 应用程序通过 Freeradius 进行 2FA
- windows - IPCONFIG 发现 ETHERNET ADAPTER 工作,我如何找到 Wi-Fi 适配器?
- c++ - 如何让用户设置 2D Vector 的行大小和列大小?
- mongodb - 在 Mac 上的 ZSH shell 中运行 mongod 并获取命令未找到
- keras - Coremltools:使最简单的卷积模型工作的错误
- pandas - 'Series' 对象是可变的,因此它们不能在尝试对列求和并且数据类型为浮点数时进行散列
- c - 链表显示分段错误错误
- java - 如何使用java返回xml文件的图像数据
- php - PHP字符串比较到一个txt
- python - .loc 删除行而不是定位 Python Pandas