跳过python中的for循环中的第一个条目?


186

在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 2013年

Answers:


268

其他答案仅适用于序列。

对于任何迭代,请跳过第一项:

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

2
我发现执行cars.pop(0)和cars.pop()效果很好。
dreamwork801 '18 -10-23

@ dreamwork801我的答案和Sven(在第一条评论中链接)适用于所有可迭代的甚至无限的迭代,因为它们不需要在迭代开始之前对数据进行O(n)运算。您的建议和Abhjit的建议都只能用于序列,而不能重复。
agf


27

跳过第一项的最佳方法是:

from itertools import islice
for car in islice(cars, 1, None):
    # do something

在这种情况下,使用起点1和终点None调用islice,表示迭代器的结束。

为了能够从可迭代对象的末尾跳过项目,您需要知道其长度(对于列表而言总是可能的,但不一定可以迭代的所有内容)。例如,islice(cars,1,len(cars)-1)将跳过汽车列表中的第一项和最后一项。


看一看Sven的(被低估的)答案。他介绍了islice很好地跳过任何可迭代项的开头和/或结尾的任意数量的项目,而不用知道长度或一次在内存中存储比绝对必要更多的项目。
2012年

Sven的答案实际上将整个迭代器存储在内存中-collections.deque将贯穿迭代器运行。尝试执行类似collections.deque(xrange(10000000))的操作。如果您想跳过第一个项目,则无需将所有整数存储在内存中
Roee Shenberg 2012年

2
An islice是传递给的deque,而不是整个迭代器,它只是末尾要跳过的项目数的长度。它不会将整个迭代器存储在内存中。
2012年

26

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

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
2012年

collections.deque(...)将立即通过迭代器。这意味着skip(xrange(10000000),1)会占用大量内存,尽管实际上不应该这样做。
罗伊·申伯格

4
@RoeeShenberg:skip(xrange(10000000), 1)将使用at_end=0,因此参数to deque()将是islice(it, 0),它将仅消耗的零个元素it。这不会占用很多内存。
Sven Marnach 2012年

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

3
请勿将其list用作变量名
Abhijit,2012年

OP只想跳过第一个元素。为什么:-1?
luke14free 2012年

6
它实际上不是保留的;名称list可以重新绑定。这就是为什么您不应该(而不是不能)使用它。
jscs 2012年

@ luke14free,这个问题说要跳过第一个元素,但是他的代码注释暗示他确实想跳过第一个和最后一个。
JerseyMike 2012年

@ luke14free就是标题所说的,不是他在代码中键入的内容:“如果是第一个或最后一个,则跳过”
KurzedMetal,2012年

3

基于@SvenMarnach的答案,但更简单并且不使用双端队列

>>> 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结果,这比双端队列解决方案要快一点

>>> 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 2015年

3

例:

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

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

for i in range(1,-1):

2

好吧,您的语法并不是真正的Python。

Python中的迭代遍历容器的内容(从技术上讲,遍历迭代器),并带有一个语法for item in container。在这种情况下,容器是cars列表,但是您要跳过第一个和最后一个元素,因此意味着cars[1:-1](python列表是从零开始的,负数从末开始计数,并且:是对语法进行切片。

所以你要

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

4
这不适用于迭代器(例如生成器),仅适用于序列。
罗伊·申伯格

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

2

这是我的首选。它不需要在循环上添加太多内容,并且仅使用内置工具即可使用。

从...来:

for item in my_items:
  do_something(item)

至:

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


1

more_itertools项目扩展itertools.islice到处理负指标。

import more_itertools as mit

iterable = 'ABCDEFGH'
list(mit.islice_extended(iterable, 1, -1))
# Out: ['B', 'C', 'D', 'E', 'F', 'G']

因此,您可以将它的slice元素优雅地应用于iterable的第一项和最后一项之间:

for car in mit.islice_extended(cars, 1, -1):
    # do something

0

我看起来是这样的,即使它看起来像个hack,但每次都可以使用:

ls_of_things = ['apple', 'car', 'truck', 'bike', 'banana']
first = 0
last = len(ls_of_things)
for items in ls_of_things:
    if first == 0
        first = first + 1
        pass
    elif first == last - 1:
        break
    else:
        do_stuff
        first = first + 1
        pass
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.