简体   繁体   English

pythonic方法迭代列表的一部分

[英]pythonic way to iterate over part of a list

I want to iterate over everything in a list except the first few elements, eg: 我想迭代列表中的所有内容,除了前几个元素,例如:

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

This is concise, but copies the whole list, which is unnecessary. 这是简洁的,但复制整个列表,这是不必要的。 I could do: 我可以:

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

But this modifies the list, which isn't always good. 但这会修改​​列表,这并不总是好的。

I can do this: 我可以做这个:

for i in xrange(2, len(lines)):
    line = lines[i]
    foo(line)

But, that's just gross. 但是,这只是粗略的。

Better might be this: 更好的可能是这个:

for i,line in enumerate(lines):
    if i < 2: continue
    foo(line)

But it isn't quite as obvious as the very first example. 但它并不像第一个例子那么明显。

So: What's a way to do it that is as obvious as the first example, but doesn't copy the list unnecessarily? 那么:这样做的方法与第一个例子一样明显,但是不会不必要地复制列表?

You can try itertools.islice(iterable[, start], stop[, step]) : 你可以尝试itertools.islice(iterable[, start], stop[, step])

import itertools
for line in itertools.islice(list , start, stop):
     foo(line)

The original solution is, in most cases, the appropriate one. 在大多数情况下,原始解决方案是合适的解决方案。

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

While this does copy the list, it is only a shallow copy, and is quite quick. 虽然这会复制列表,但它只是一个浅层副本,并且非常快。 Don't worry about optimizing until you have profiled the code and found this to be a bottleneck. 在分析代码并发现这是一个瓶颈之前,不要担心优化。

Although itertools.islice appears to be the optimal solution for this problem, somehow, the extra import just seems like overkill for something so simple. 虽然itertools.islice似乎是这个问题的最佳解决方案,但是不知何故,额外的导入对于这么简单的东西来说似乎有些过分。

Personally, I find the enumerate solution perfectly readable and succinct - although I would prefer to write it like this: 就个人而言,我发现enumerate解决方案完全可读且简洁 - 虽然我更喜欢这样写:

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

You might build a helper generator: 您可以构建一个辅助生成器:

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

Now you can for i in skip_heading( lines, 2 ): without worrying. 现在你可以for i in skip_heading( lines, 2 ):不用担心。

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

I prefer to use dropwhile for this. 我更喜欢使用dropwhile It feels natural after using it in Haskell and some other languages, and seems reasonably clear. 在Haskell和其他一些语言中使用它后感觉很自然,并且看起来相当清楚。 You can also use it in many other cases where you want to look for a "trigger" condition more complex than the item's index for the start of the iteration. 您还可以在许多其他情况下使用它,在这种情况下,您希望查找比项目的迭代开始索引更复杂的“触发器”条件。

from itertools import dropwhile

for item in dropwhile(lambda x: x[0] < 2, enumerate(lst)):
  # ... do something with item

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM