在Python中的for循环中如何跳过第一个元素?

273
在Python中,我该如何实现以下操作:
for car in cars:
   # Skip first and last, do work for rest

4
我是一名新手,但我已经在使用 for n, i in enumerate(cars): if n!= 0: do something to i。这个逻辑是为每个值添加一个“计数器”,然后可以通过 if n == some_value 来定位它。在这个例子中,它将对除第一个实例之外的每个 i 进行某些操作。 - user1063287
15个回答

519

要在Python中跳过第一个元素,您可以简单地编写

for car in cars[1:]:
    # Do What Ever you want

或者跳过最后一个元素
for car in cars[:-1]:
    # Do What Ever you want

您可以将此概念用于任何序列(不过不能用于任何可迭代对象)。


72
不是适用于所有的可迭代对象,但适用于所有的序列。 - Sven Marnach
8
内存使用情况如何?slice 会创建子序列的副本吗? - Voyager
3
@Voyager 是的,它会创建一份新的副本。 - Srinivas Reddy Thatiparthy

332

其他答案仅适用于序列。

对于任何可迭代对象,要跳过第一个项目:

itercars = iter(cars)
next(itercars)
for car in itercars:
    # do work

如果你想跳过最后一个元素,可以这样做:

itercars = iter(cars)
# add 'next(itercars)' here if you also want to skip the first
prev = next(itercars)
for car in itercars:
    # do work on 'prev' not 'car'
    # at end of loop:
    prev = car
# now you can do whatever you want to do to the last one on 'prev'

1
另请参见Sven Marnach答案 - agf
2
我发现使用 cars.pop(0) 和 cars.pop() 很有效。 - dreamwork801
1
@dreamwork801 我的回答和Sven的回答,我在第一条评论中提供了链接,适用于任何可迭代对象,甚至是无限的,因为它们在迭代开始之前不需要对数据进行O(n)操作。你和Abhjit的建议只适用于序列,而不是任何可迭代对象。 - agf

50

跳过第一个或多个项目的最佳方法是:

from itertools import islice
for car in islice(cars, 1, None):
    pass
    # do something
在这种情况下,islice被调用时,起始点为1,结束点为None,表示iterable的结尾。

如果要从一个iterable中跳过末尾的项,则需要知道其长度(对于列表总是可能的,但不一定适用于所有可以迭代的对象)。例如,islice(cars, 1, len(cars)-1)将跳过cars中的第一个和最后一个项。


看看Sven(被低估的)的答案。他很好地涵盖了如何使用islice跳过任意数量的可迭代对象开头和/或结尾的项,而不知道长度或一次在内存中存储更多的项比绝对必要的少。 - agf
Sven的答案实际上会将整个迭代器存储在内存中 - collections.deque将遍历迭代器。尝试执行类似collections.deque(xrange(10000000))的操作。如果要跳过第一个项目,则无需将所有int都存储在内存中... - Roee Shenberg
2
islice 是传递给 deque 的内容,而不是整个迭代器,并且它仅表示要跳过的项目数量的长度。它不会将整个迭代器存储在内存中。 - agf

31

这里有一个更通用的生成器函数,它可以跳过可迭代对象开头和结尾的任意数量的项目:

def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    for x in itertools.islice(it, at_start):
        pass
    queue = collections.deque(itertools.islice(it, at_end))
    for x in it:
        queue.append(x)
        yield queue.popleft()

使用示例:

>>> list(skip(range(10), at_start=2, at_end=2))
[2, 3, 4, 5, 6, 7]

可能需要为 at_end == 0 添加快速路径。 - agf
collections.deque(...)会立即遍历迭代器。这意味着skip(xrange(10000000), 1)将占用大量内存,尽管它实际上不应该这样做。 - Roee Shenberg
4
@RoeeShenberg: skip(xrange(10000000), 1)会使用at_end=0,因此deque()的参数将是islice(it, 0),它只会消耗it的零个元素。这不会占用太多内存。 - Sven Marnach

15

这段代码跳过了列表的第一个和最后一个元素:

for item in list_name[1:-1]:
    #...do whatever

3
不要将“list”用作变量名。 - Abhijit
2
OP想要跳过第一个元素,为什么要用":-1"? - luke14free
8
实际上,list并没有被保留;这个名称可以被重新绑定。所以你 不应该 而不是 不能 使用它。 - jscs
@luke14free,问题说要跳过第一个元素,但他的代码注释暗示他实际上想跳过第一个和最后一个。 - JerseyMike
1
@luke14free,这是标题上的内容,而不是他在代码中输入的内容:“如果是第一个或最后一个则跳过”。 - KurzedMetal
好的,这只是出于好奇心...老实说,我甚至不知道OP在使用什么编程语言。 - luke14free

6

例子:

mylist=['one','two','three','four','five']
for i in mylist[1:]:
   print(i)

在Python中,索引从0开始,我们可以使用切片操作来进行迭代中的操作。

for i in range(1,-1):

5

这是我的首选方案。它不需要在循环中添加太多内容,只使用内置工具。

从以下状态开始:

for item in my_items:
  do_something(item)

to:

for i, item in enumerate(my_items):
  if i == 0:
    continue
  do_something(item)

3

嗯,您的语法实际上不是Python。

在Python中,迭代是针对容器的内容进行的(技术上是针对迭代器的),语法为 for item in container 。在这种情况下,容器是 cars 列表,但您想跳过第一个和最后一个元素,所以这意味着使用 cars [1:-1] (Python列表从0开始计数,负数表示从末尾开始计数,是切片语法)。

所以您需要

for c in cars[1:-1]:
    do something with c

4
这无法与可迭代对象(例如生成器)一起使用,只能与序列一起使用。 - Roee Shenberg

2

基于 @SvenMarnach 的答案,但更简单且不使用 deque

>>> def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    it = itertools.islice(it, at_start, None)
    it, it1 = itertools.tee(it)
    it1 = itertools.islice(it1, at_end, None)
    return (next(it) for _ in it1)

>>> list(skip(range(10), at_start=2, at_end=2))
[2, 3, 4, 5, 6, 7]
>>> list(skip(range(10), at_start=2, at_end=5))
[2, 3, 4]

请注意,根据我的timeit结果,这种方法比deque解决方案稍微快一些。

>>> iterable=xrange(1000)
>>> stmt1="""
def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    it = itertools.islice(it, at_start, None)
    it, it1 = itertools.tee(it)
    it1 = itertools.islice(it1, at_end, None)
    return (next(it) for _ in it1)
list(skip(iterable,2,2))
    """
>>> stmt2="""
def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    for x in itertools.islice(it, at_start):
        pass
    queue = collections.deque(itertools.islice(it, at_end))
    for x in it:
        queue.append(x)
        yield queue.popleft()
list(skip(iterable,2,2))
        """
>>> timeit.timeit(stmt = stmt1, setup='from __main__ import iterable, skip, itertools', number = 10000)
2.0313770640908047
>>> timeit.timeit(stmt = stmt2, setup='from __main__ import iterable, skip, itertools, collections', number = 10000)
2.9903135454296716

通过使用 tee(),你仍然会为生成器(即 it1)在内存中创建一个完整的列表,对吗? - Jabberwockey

2

另一种方法:

for idx, car in enumerate(cars):
    # Skip first line.
    if not idx:
        continue
    # Skip last line.
    if idx + 1 == len(cars):
        continue
    # Real code here.
    print car

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接