代码之家  ›  专栏  ›  技术社区  ›  Bartosz Radaczyński

循环时如何访问上一个/下一个元素?

  •  41
  • Bartosz Radaczyński  · 技术社区  · 17 年前

    有没有办法访问 list 是(或 tuple ,或其他iterable的)下一个或上一个元素,同时使用 for

    l = [1, 2, 3]
    for item in l:
        if item == 2:
            get_previous(l, item)
    
    12 回复  |  直到 6 年前
        1
  •  77
  •   Markus Jarderot    9 年前

    表示为生成函数:

    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
    
        2
  •  34
  •   Boris Verkhovskiy Brian Clapper    6 年前
    l = [1, 2, 3]
    
    for i, j in zip(l, l[1:]):
        print(i, j)
    
        3
  •  12
  •   Boris Verkhovskiy Brian Clapper    6 年前
    l = [1, 2, 3]
    for i, item in enumerate(l):
        if item == 2:
            previous = l[i - 1]
            print(previous)
    

    输出:

    1
    

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

        4
  •  10
  •   Brian    17 年前

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

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

    在前向/后向情况下使用时,如果还需要在没有下一个或上一个值的情况下处理数字,则可能需要在序列中填充适当的值,例如“无”。

    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)
    
        5
  •  8
  •   RattleyCooper    9 年前

    我知道这很旧,但为什么不直接使用它呢 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
    

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

        6
  •  5
  •   codeape    17 年前

    请从中查看looper实用程序 Tempita project 。它为循环项提供一个包装器对象,该对象提供属性,如previous、next、first、last等。

    看一看 source code 对于looper类来说,它非常简单。还有其他这样的循环助手,但我现在记不起其他的了。

    例子:

    > 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
    
        7
  •  3
  •   Boris Verkhovskiy Brian Clapper    6 年前

    如果你想解决iterables的问题 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)
    
        8
  •  1
  •   S.Lott    17 年前

    就在之前?

    你指的是以下内容,对吗?

    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
    
        9
  •  1
  •   Boris Verkhovskiy Brian Clapper    6 年前

    我不认为有直接的方法,尤其是因为iterable可以是 generator (不要回去)。你可以用 sequences 通过将元素的索引传递到循环体:

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

    这个 enumerate() 函数是内置的。

        10
  •  1
  •   deeenes    6 年前

    我知道这是一个老问题,但我发现展示一个简单的解决方案很重要,这个解决方案也适用于生成器和其他类型的iterables,不像大多数答案只适用于类似列表的对象。这与Brian的答案和这里的解决方案有些相似: 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 在第二个iterable上(如果您确定它至少有一个元素):

    import itertools
    
    iter0, iter1 = itertools.tee(iterable)
    _ = next(iter1)
    
    for item, next_item in itertools.zip_longest(iter0, iter1):
    
        do_something(item, next_item)
    
        11
  •  1
  •   kosciej16    4 年前

    对于任何升级到python 3.10的人来说,这样的函数都是直接添加到 itertools

    import itertools
    
    l = [1,2,3]
    for x, y in itertools.pairwise(l):
        print(x, y)
    # 1 2
    # 2 3
    
        12
  •  1
  •   InhirCode    4 年前

    如果您不想导入任何内容,下面是一个使用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(),默认参数。

        13
  •  0
  •   chirag    17 年前

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

    如果要迭代列表或元组,enumerate(iterable)可能很有用。

        14
  •  -2
  •   Emilio M Bumachar    15 年前

    虽然不是很像蟒蛇,但它很简单:

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

    方法:保护边缘

        15
  •  -7
  •   Aaron Digulla    17 年前

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

    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]