我想迭代列表中的所有内容,除了前几个元素,例如:
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)
但它并不像第一个例子那么明显。
所以:有什么方法可以做到这一点,就像第一个例子一样明显,但不会不必要地复制列表?
答案 0 :(得分:40)
您可以尝试itertools.islice(iterable[, start], stop[, step])
:
import itertools
for line in itertools.islice(list , start, stop):
foo(line)
答案 1 :(得分:8)
虽然itertools.islice
似乎是这个问题的最佳解决方案,但不知何故,额外的导入对于这么简单的东西来说似乎有些过分。
就个人而言,我发现enumerate
解决方案完全可读且简洁 - 尽管我更喜欢这样写:
for index, line in enumerate(lines):
if index >= 2:
foo(line)
答案 2 :(得分:8)
在大多数情况下,原始解决方案是合适的解决方案。
for line in lines[2:]:
foo(line)
虽然这会复制列表,但它只是一个浅层副本,并且非常快。在分析代码并发现这是一个瓶颈之前,不要担心优化。
答案 3 :(得分:4)
您可以构建一个辅助生成器:
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)
答案 4 :(得分:3)
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 ):
而不用担心。
答案 5 :(得分:3)
for fooable in (line for i,line in enumerate(lines) if i >= 2):
foo(fooable)
答案 6 :(得分:3)
我更喜欢使用dropwhile。在Haskell和其他一些语言中使用它后感觉很自然,并且看起来相当清楚。您还可以在许多其他情况下使用它,在这种情况下,您希望查找比项目的迭代开始索引更复杂的“触发器”条件。
from itertools import dropwhile
for item in dropwhile(lambda x: x[0] < 2, enumerate(lst)):
# ... do something with item