Как получить доступ к предыдущему/следующему элементу во время цикла?

Есть ли способ получить доступ к списку (или кортежу или другому повторимому) далее или предыдущему элементу во время цикла с циклом for?

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

Ответ 1

Выражается как функция генератора:

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

Один простой способ.

l=[1,2,3]
for i,j in zip(l, l[1:]):
    print i, j

Ответ 3

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

>>>1

Ответ 4

Когда вы имеете дело с генераторами, в которых вам нужен какой-то контекст, я часто использую приведенную ниже функцию утилиты, чтобы получить скользящее окно на итераторе:

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

Проверьте утилиту looper из проекта Tempita. Он предоставляет объект-обертку вокруг элемента цикла, который предоставляет такие свойства, как предыдущий, следующий, первый, последний и т.д.

Взгляните на исходный код для класса 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

Ответ 6

Я знаю, что это старо, но почему бы просто не использовать 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

Если вы запустите это, вы увидите, что он захватывает предыдущие и следующие элементы и не заботится о повторении элементов в списке.

Ответ 7

Я не думаю, что есть простой способ, особенно, что итерабель может быть генератором (не возвращаться). Там есть достойное обходное решение, полагающееся на явное пропускание индекса в тело цикла:

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

Функция enumerate() является встроенной.

Ответ 8

Итераторы имеют только метод next(), поэтому вы не можете смотреть вперед или назад, вы можете получить только следующий элемент.

enumerate (iterable) может быть полезна, если вы повторяете список или кортеж.

Ответ 9

Непосредственно предыдущий?

Вы имеете в виду следующее, верно?

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

Ответ 10

Если вы хотите, чтобы решение работало над итерами, itertools 'docs имеет рецепт, который делает именно то, что вы хотите:

import itertools

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

Если вы используете Python 2.x, используйте itertools.izip вместо zip

Ответ 11

Не очень pythonic, но делает это и прост:

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

ДЕЛАТЬ: защитить края

Ответ 12

Самый простой способ - найти список для элемента:

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]