pythonic方法迭代列表的一部分

时间:2011-12-29 17:44:04

标签: python

我想迭代列表中的所有内容,除了前几个元素,例如:

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)

但它并不像第一个例子那么明显。

所以:有什么方法可以做到这一点,就像第一个例子一样明显,但不会不必要地复制列表?

7 个答案:

答案 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