迭代列表和删除元素的最佳方法是什么?我正在做的当前方式导致跳过元素

时间:2018-06-15 01:20:34

标签: python python-3.x

我正在使用此方法,但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]

但感觉不对。

1 个答案:

答案 0 :(得分:3)

迭代期间的变异是不好的

首先,改变你正在迭代的列表几乎不是一个好主意。特别是,这是您当前问题的来源。让我们来看一个类似的例子。

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循环相比,它的速度非常快。

这是获得最后三个元素的最快方法。