【问题标题】:How to access the previous/next element in a for loop?如何访问 for 循环中的上一个/下一个元素?
【发布时间】:2010-09-24 08:05:33
【问题描述】:

有没有办法在使用for 循环遍历它时访问list(或tuple,或其他可迭代的)下一个或上一个元素?

l = [1, 2, 3]
for item in l:
    if item == 2:
        get_previous(l, item)

【问题讨论】:

    标签: python for-loop


    【解决方案1】:

    迭代器只有 next() 方法,所以你不能向前或向后看,你只能得到下一项。

    enumerate(iterable) 在迭代列表或元组时会很有用。

    【讨论】:

      【解决方案2】:

      最简单的方法是在列表中搜索项目:

      def get_previous(l, item):
          idx = l.find(item)
          return None if idx == 0 else l[idx-1]
      

      当然,这仅适用于列表仅包含唯一项目的情况。另一种解决方案是:

      for idx in range(len(l)):
          item = l[idx]
          if item == 2:
              l[idx-1]
      

      【讨论】:

        【解决方案3】:

        我认为没有直接的方法,尤其是因为可迭代对象可以是 generator(没有回头路)。您可以使用sequences 将元素的索引传递到循环体中:

        for index, item in enumerate(l):
            if index > 0:
                previous_item = l[index - 1]
            else:
                previous_item = None 
        

        enumerate() 函数是内置函数。

        【讨论】:

          【解决方案4】:

          表示为生成器函数:

          def neighborhood(iterable):
              iterator = iter(iterable)
              prev_item = None
              current_item = next(iterator)  # throws StopIteration if empty.
              for next_item in iterator:
                  yield (prev_item, current_item, next_item)
                  prev_item = current_item
                  current_item = next_item
              yield (prev_item, current_item, None)
          

          用法:

          for prev,item,next in neighborhood(l):
              print prev, item, next
          

          【讨论】:

          • 在这种情况下,我可能会执行“prev, item = item, next”。
          • 要无限循环(无 StopIteration),请执行 from itertools import cycle 并将第二行更改为:iterator = cycle(iterable)
          • 在这种情况下使用 enumerate 是不是不太像 Pythonic?
          • 您正在寻找的答案是 Vicky Liau 的,在这个下面的那个。或者,如果您希望它适用于任何可迭代而不仅仅是列表/元组/strs 等,one using itertools.
          • 对于 python 3.10 - 用户可以使用 itertools.pairwise 函数,请参阅 stackoverflow.com/a/69584524/3361462
          【解决方案5】:

          在处理需要一些上下文的生成器时,我经常使用以下实用函数在迭代器上提供滑动窗口视图:

          import collections, itertools
          
          def window(it, winsize, step=1):
              """Sliding window iterator."""
              it=iter(it)  # Ensure we have an iterator
              l=collections.deque(itertools.islice(it, winsize))
              while 1:  # Continue till StopIteration gets raised.
                  yield tuple(l)
                  for i in range(step):
                      l.append(it.next())
                      l.popleft()
          

          它会一次生成一个序列 N 项的视图,移动步骤。例如。

          >>> list(window([1,2,3,4,5],3))
          [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
          

          当在前瞻/后视情况下使用时,您还需要处理没有下一个或前一个值的数字,您可能需要使用适当的值(例如 None)填充序列。

          l= range(10)
          # Print adjacent numbers
          for cur, next in window(l + [None] ,2):
              if next is None: print "%d is the last number." % cur
              else: print "%d is followed by %d" % (cur,next)
          

          【讨论】:

          【解决方案6】:

          紧接在前?

          你的意思是下面的,对吧?

          previous = None
          for item in someList:
              if item == target: break
              previous = item
          # previous is the item before the target
          

          如果你想要 n 个之前的项目,你可以用一种大小为 n 的循环队列来做到这一点。

          queue = []
          for item in someList:
              if item == target: break
              queue .append( item )
              if len(queue ) > n: queue .pop(0)
          if len(queue ) < n: previous = None
          previous = previous[0]
          # previous is *n* before the target
          

          【讨论】:

            【解决方案7】:
            l = [1, 2, 3]
            for i, item in enumerate(l):
                if item == 2:
                    previous = l[i - 1]
                    print(previous)
            

            输出:

            1
            

            如果您要查找的项目是列表中的第一项,这将环绕并返回列表中的最后一项。换句话说,将上述代码中的第三行更改为if item == 1: 将导致它打印3

            【讨论】:

            • 如果你的列表只有一个元素l = [2],这将返回与前一个元素相同的元素。
            【解决方案8】:

            查看Tempita project 中的looper 实用程序。它为您提供了一个围绕循环项目的包装器对象,该对象提供诸如上一个、下一个、第一个、最后一个等属性。

            看一下looper类的source code,很简单。还有其他这样的循环助手,但我现在不记得其他任何人了。

            例子:

            > easy_install Tempita
            > python
            >>> from tempita import looper
            >>> for loop, i in looper([1, 2, 3]):
            ...     print loop.previous, loop.item, loop.index, loop.next, loop.first, loop.last, loop.length, loop.odd, loop.even
            ... 
            None 1 0 2 True False 3 True 0
            1 2 1 3 False False 3 False 1
            2 3 2 None False True 3 True 0
            

            【讨论】:

            • 链接都坏了。
            【解决方案9】:

            不是很pythonic,但可以完成并且很简单:

            l=[1,2,3]
            for index in range(len(l)):
                if l[index]==2:
                    l[index-1]
            

            TO DO:保护边缘

            【讨论】:

            【解决方案10】:

            我知道这是旧的,但为什么不直接使用enumerate

            l = ['adam', 'rick', 'morty', 'adam', 'billy', 'bob', 'wally', 'bob', 'jerry']
            
            for i, item in enumerate(l):
                if i == 0:
                    previous_item = None
                else:
                    previous_item = l[i - 1]
            
                if i == len(l) - 1:
                    next_item = None
                else:
                    next_item = l[i + 1]
            
                print('Previous Item:', previous_item)
                print('Item:', item)
                print('Next Item:', next_item)
                print('')
            
                pass
            

            如果你运行它,你会看到它会抓取上一个和下一个项目,而不关心列表中的重复项目。

            【讨论】:

            • 为什么投反对票?这很好,不涉及外部库或特殊功能。
            • 该问题还要求上一项。如果一个项目重复,这不会错误地工作吗? [1,2,1,3]?
            • @Teepeemm,是的,我会更新一个符合要求的版本。
            【解决方案11】:
            l = [1, 2, 3]
            
            for i, j in zip(l, l[1:]):
                print(i, j)
            

            【讨论】:

            • 我使用了这个,但为了避免删除开始/结束项而进行了扩展:for prev,cur,next in zip([None]+l[:-1], l, l[1:]+[None]):
            • 您可以避免像这样删除开始/结束项目:l = [None, *l, None] 然后for prev, cur, nxt in zip(l, l[1:], l[2:]):
            【解决方案12】:

            如果您希望解决方案适用于可迭代对象,itertools documentation 有一个配方可以使用 itertools.tee() 完全满足您的需求:

            import itertools
            
            def pairwise(iterable):
                "s -> (s0,s1), (s1,s2), (s2, s3), ..."
                a, b = itertools.tee(iterable)
                next(b, None)
                return zip(a, b)
            

            【讨论】:

              【解决方案13】:

              我知道这是一个老问题,但我发现展示一个简单的解决方案很重要,该解决方案也适用于生成器和其他类型的可迭代对象,而不像大多数仅适用于列表类对象的答案。这有点类似于布赖恩的回答和这里的解决方案:https://www.programcreek.com/python/example/1754/itertools.tee

              import itertools
              
              iter0, iter1 = itertools.tee(iterable)
              
              for item, next_item in itertools.zip_longest(
                  iter0,
                  itertools.islice(iter1, 1, None)
              ):
              
                  do_something(item, next_item)
              

              或者,在第二个可迭代对象上调用 next(如果您确定它至少有一个元素):

              import itertools
              
              iter0, iter1 = itertools.tee(iterable)
              _ = next(iter1)
              
              for item, next_item in itertools.zip_longest(iter0, iter1):
              
                  do_something(item, next_item)
              

              【讨论】:

                【解决方案14】:

                对于升级到python 3.10的任何人,该功能直接添加到 itertools

                import itertools
                
                l = [1,2,3]
                for x, y in itertools.pairwise(l):
                    print(x, y)
                # 1 2
                # 2 3
                

                【讨论】:

                  【解决方案15】:

                  如果您不想导入任何内容,这里是一个使用 for 循环访问生成器上一项的示例。它使用类变量在下一次调用之前存储每个下一个结果。如果您想要的不仅仅是前一个项目,这个变量可能是一个小列表。类内部是一个方法生成器,它有效地扩展了 next() 内置函数以包含上一个项目分配。

                  代码(Python 3.10):

                  def previous():
                      class Plusprev():
                          def __init__(pp, gen=None):
                              pp.g = gen
                              pp.nxt = ''
                              pp.prev = 'start'
                  
                          def ppnext(pp):
                              while pp.nxt != 'done':
                                  pp.nxt = next(pp.g,'done')
                                  yield pp.nxt
                                  pp.prev = pp.nxt
                  
                      sqgen = (n*n for n in range(13))
                      ppcl = Plusprev(sqgen)
                      nxtg = ppcl.ppnext()
                      nxt = next(nxtg,'done')
                      while nxt != 'done':
                          print('\nprevious ',ppcl.prev)
                          print('current ',nxt)
                          nxt = next(nxtg,'done')
                  
                  previous()
                  

                  这使用了内置函数,next(),默认参数。

                  【讨论】:

                    猜你喜欢
                    • 2010-09-24
                    • 2021-09-24
                    • 1970-01-01
                    • 2020-08-02
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-04-01
                    • 2016-03-06
                    相关资源
                    最近更新 更多