遍历列表的一部分的Python方法

遍历列表的一部分的Python方法,python,list,iteration,Python,List,Iteration,我想迭代列表中的所有元素,但前几个元素除外,例如: 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) 但是,那太恶心了 最好是这样: f

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

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)
对于i,枚举中的行(行):
如果i<2:继续
傅(行)
但这并不像第一个例子那么明显

那么:有什么方法可以做到与第一个例子一样明显,但不会不必要地复制列表

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
现在,您可以在跳过标题(第2行)中对i进行
而不用担心。

您可以尝试:


您可以构建辅助生成器:

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)
我更喜欢用这个。在Haskell和其他一些语言中使用后,感觉很自然,而且看起来相当清晰。您还可以在许多其他情况下使用它,在这些情况下,您希望在迭代开始时查找比项目索引更复杂的“触发器”条件

from itertools import dropwhile

for item in dropwhile(lambda x: x[0] < 2, enumerate(lst)):
  # ... do something with item
从itertools导入dropwhile
对于dropwhile中的项(lambda x:x[0]<2,枚举(lst)):
# ... 对这个项目做些什么

虽然
itertools.islice
似乎是这个问题的最佳解决方案,但不知何故,对于如此简单的事情来说,额外的导入似乎有些过火了

就我个人而言,我觉得
枚举
解决方案非常可读和简洁,尽管我更喜欢这样写:

for index, line in enumerate(lines):
    if index >= 2:
        foo(line)

在大多数情况下,最初的解决方案是合适的

for line in lines[2:]:
    foo(line)


虽然这确实复制了列表,但它只是一个肤浅的副本,而且相当快。在分析代码并发现这是一个瓶颈之前,不要担心优化。

我认为
对于我在xrange(2,len(行)):
是可以的。我知道这并不能回答你的问题,但对于300行文本,我根本不担心复制。请记住,只复制引用,而不是字符串数据本身……我个人最喜欢您放的第四个示例。它的效率不亚于
islice
方法,而且在我看来,任何查看您的代码的人都会更容易阅读和理解。我也认为
对于我在xrange(2,len(line))
中的表现很好,并且比下面的任何选择都好。为什么你认为它是“恶心的?”@BlueRaja DannyPflughoeft:因为pythonic的迭代方式是对每个
循环使用
,对stuff:
中的x使用
。对于xrange中的i(len(stuff)):x=stuff[i]
,您不需要执行
。。那么,如果您只想进行相同的迭代,但略有不同,为什么要这样做呢?这基本上是
itertools.islice
@delnan:同意的一个特例。它有点可扩展。有时真正的问题是头/尾处理,其中头有一种处理,尾有一种不同的处理。这是如何工作的?我只是把它复制到一个小的测试项目中,它没有打印任何东西——这也是我期望它做的。我遗漏了什么吗?在该函数中,
似乎未被使用。我认为您有一个输入错误/bug。@S.Lott我没有用python编写太多代码,假设代码中有一个bug,我第一眼就不明白,这不是我想做的;)您的修复非常简单,因此没有隐藏任何聪明的技巧,但谁知道呢。@NullUserException干杯!我本来打算加上这个,但是我的公司出了个小问题,这会很可怕的是:
对于lazy中的line(list)[:2]:foo(line)
,其中
lazy
包装了iterable,如果你对它进行切片,则调用
islice
,等等。这样它看起来就像一个切片(应该是这样的).@Claudiu as slice应该是与切片对象类型相同的对象,这意味着lazy()创建了一个迭代器。是的,圭多反对这个想法。这不会停止独立的实现,但您不会很快在标准库中看到它。警告:与
list1[start:stop]
相比,它的效率极低。例如,
islice(list1、100000、100100)
将首先迭代前99999个值(只是不会返回它们)。用cProfile自己试试;文档中也有这种情况。@Jeff在调用next
start-1
times会加重列表片内存分配的情况下,投票支持这种情况。OP在他的问题中特别提到列表切片是一种不希望的解决方案。但它仅限于列表,对于任意的iterables不起作用。@s.Lott您当然是对的。但它符合OP的要求,是我想到的第一件事——不幸的是,我没有像其他人一样记住itertools的所有功能;-)啊,就我个人而言,我希望缩进越少越好。首先检查+continue/return/break/etc的错误,然后检查其余的错误-through@Claudiu:你所说的话也能立即传达出你的意图;您不需要查看
if
块的末尾,就可以查看后面或
else
块中是否发生了任何事情。@ChrisMorgan。多就是少。在本例中,单独的
continue
将在代码中创建一个冗余分支,不必要地迫使读取器解析两个代码块,而不是一个。如果循环中的代码更复杂,那么
continue
语句肯定可以通过减少缩进来提高可读性。但这并不是这个例子想要说明的。@Ekhumaro:事实上,这取决于块的长度。我当然不会用不到六行的篇幅继续写下去。。。。但是如果你知道你将要处理成千上万个元素的列表,不要嘲笑像
itertools.islice
这样的礼物。在这种情况下,值得一看。@ChrisMorgan:“在大多数情况下”这句话并不是在嘲笑。即使它没有针对大型列表进行优化,这段代码的优点是对于小型列表具有可读性。
for index, line in enumerate(lines):
    if index >= 2:
        foo(line)
for line in lines[2:]:
    foo(line)