【问题标题】:Skip first entry in for loop in python?在python中跳过for循环的第一个条目?
【发布时间】:2012-04-22 04:20:09
【问题描述】:

在python中,我该怎么做:

for car in cars:
   # Skip first and last, do work for rest

【问题讨论】:

  • 我是新手,但我一直在使用for n, i in enumerate(cars): if n!= 0: do something to i。逻辑是它为每个值添加一个“计数器”,然后您可以将其作为目标,例如if n == some_value。在这个例子中,它会对 i 的每个实例做一些事情,除了第一个实例。

标签: python


【解决方案1】:

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

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 在任何可迭代的开头和/或结尾跳过任意数量的项目,而不知道长度或一次在内存中存储的项目超过绝对必要的数量。
  • Sven 的答案实际上会将整个迭代器存储在内存中 - collections.deque 将运行通过迭代器。尝试做类似 collections.deque(xrange(10000000)) 的事情。如果您想跳过第一项,则无需将所有整数存储在内存中...
  • 一个islice 是传递给deque 的内容,而不是整个迭代器,它只是最后要跳过的项目数的长度。它不会将整个迭代器存储在内存中。
【解决方案2】:

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

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

或跳过最后一个元素

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

您可以将此概念用于任何sequence(但不适用于任何iterable)。

【讨论】:

  • 不是所有iterables,而是所有sequences
  • 内存使用情况如何? slice 是否会生成子序列的新副本?
  • @Voyager 是的,它确实制作了新副本。
【解决方案3】:

例子:

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

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

for i in range(1,-1):

【讨论】:

    【解决方案4】:

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

    从:

    for item in my_items:
      do_something(item)
    

    到:

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

    【讨论】:

      【解决方案5】:

      我就是这样做的,尽管它看起来像一个 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
      

      【讨论】:

        【解决方案6】:

        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']
        

        因此,您可以优雅地在可迭代对象的第一项和最后一项之间应用切片元素:

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

        【讨论】:

          【解决方案7】:

          另一种方法:

          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
          

          【讨论】:

            【解决方案8】:

            基于@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
            【解决方案9】:

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

            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添加一个快速路径。
            • collections.deque(...) 将立即通过迭代器。这意味着 skip(xrange(10000000), 1) 将占用大量内存,即使它确实不应该。
            • @RoeeShenberg: skip(xrange(10000000), 1) 将使用at_end=0,因此deque() 的参数将是islice(it, 0),它只会消耗it 的零个元素。这不会占用太多内存。
            【解决方案10】:
            for item in do_not_use_list_as_a_name[1:-1]:
                #...do whatever
            

            【讨论】:

            • 不要使用list作为变量名
            • OP 只想跳过第一个元素。为什么:-1?
            • 实际上并没有保留;名称list 可以重新绑定。这就是为什么你不应该,而不是不能,使用它。
            • @luke14free,问题是跳过第一个元素,但他的代码注释暗示他真的想先跳过,最后跳过。
            • @luke14free 这就是标题所说的,而不是他在代码中输入的内容:“跳过第一个或最后一个”
            【解决方案11】:

            嗯,你的语法一开始就不是真正的 Python。

            Python 中的迭代在容器的内容之上(嗯,从技术上讲,它在迭代器之上),语法为for item in container。在这种情况下,容器是cars 列表,但您想跳过第一个和最后一个元素,这意味着cars[1:-1](python 列表从零开始,负数从末尾开始计数,: 是切片语法。

            所以你想要

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

            【讨论】:

            • 这不适用于可迭代对象(例如生成器),只能用于序列。
            【解决方案12】:

            其他答案仅适用于序列。

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

            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'
            

            【讨论】:

            • 我发现做cars.pop(0) 和cars.pop() 效果很好。
            • @dreamwork801 我的答案和我在第一条评论中链接的 Sven 的答案适用于任何可迭代的,甚至是无限的,因为它们不需要在迭代开始之前对数据进行 O(n) 操作.你的建议和 Abhjit 的建议都只适用于序列,而不是任何可迭代的。
            【解决方案13】:

            如果cars 是一个序列,你可以这样做

            for car in cars[1:-1]:
                pass
            

            【讨论】:

              猜你喜欢
              • 2023-01-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多