pythonic的方式迭代列表的一部分
我想遍历列表中除前几个元素外的所有内容,例如:
for line in lines[2:]: foo(line)
这是简洁的,但复制整个列表,这是不必要的。 我可以:
del lines[0:2] for line in lines: foo(line)
但是这个修改列表,这并不总是好的。
我可以做这个:
for i in xrange(2, len(lines)): line = lines[i] foo(line)
但是,这只是毛病。
更好的可能是这样的:
for i,line in enumerate(lines): if i < 2: continue foo(line)
但这并不像第一个例子那么明显。
所以:做什么的方法与第一个例子一样明显,但不会不必要地复制列表?
你可以尝试itertools.islice(iterable[, start], stop[, step])
:
import itertools for line in itertools.islice(list , start, stop): foo(line)
虽然itertools.islice
似乎是这个问题的最佳解决scheme,不知何故,额外的导入似乎是如此简单的东西矫枉过正。
就个人而言,我发现enumerate
解决scheme完全可读和简洁 – 虽然我宁愿写这样的:
for index, line in enumerate(lines): if index >= 2: foo(line)
在大多数情况下,最初的解决scheme是适当的解决scheme。
for line in lines[2:]: foo(line)
虽然这样做复制列表,它只是一个浅的副本,并且相当快。 不要担心优化,直到你已经分析了代码,发现这是一个瓶颈。
for fooable in (line for i,line in enumerate(lines) if i >= 2): foo(fooable)
我更喜欢用这个。 在Haskell和其他一些语言中使用它后感觉很自然,看起来很合理。 您还可以在许多其他情况下使用它,在这种情况下,您希望查找比迭代开始时的项目索引更复杂的“触发”条件。
from itertools import dropwhile for item in dropwhile(lambda x: x[0] < 2, enumerate(lst)): # ... do something with item
你可以build立一个辅助生成器:
def rangeit(lst, rng): for i in rng: yield lst[i] for e in rangeit(["A","B","C","D","E","F"], range(2,4)): print(e)
def skip_heading( iterable, items ): the_iter= iter( iterable ): for i, e in enumerate(the_iter): if i == items: break for e in the_iter: yield e
现在你可以for i in skip_heading( lines, 2 ):
无需担心。