





Итераторы имеют только метод next (), поэтому вы не можете смотреть вперед или назад, вы можете получить только следующий элемент.
enumerate (iterable) может быть полезен, если вы выполняете итерацию списка или кортежа.
Самый простой способ - найти элемент в списке:
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]
Я не думаю, что есть простой способ, особенно потому, что итерация может быть генератор (без возврата). Вы можете сделать это с помощью последовательности, передав индекс элемента в тело цикла:
for index, item in enumerate(l):
if index > 0:
previous_item = l[index - 1]
else:
previous_item = None
Выражается как функция генератора:
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
Чтобы сделать этот цикл бесконечным (без StopIteration), выполните from itertools import cycle и измените вторую строку на: iterator = cycle(iterable)
Неужели в этом контексте менее Pythonic использовать enumerate?
Ответ, который вы ищете, - это ответ Вики Ляу, тот, что ниже этого. Или, если вы хотите, чтобы он работал с любыми итерациями, а не только со списками / кортежами / строками и т. д., один с использованием itertools.
Просто сделайте for prev, cur, nxt in zip(l, l[1:], l[2:]): вместо всего этого кода. Если вам нужно установить prev и nxt на None для первой и последней итерации, просто выполните l = [None, *l, None] перед циклом for.
Попытка использовать это в пустом списке вызывает RuntimeError (потому что это вызывает ошибку StopIteration).
Выбрасывание StopIteration является нормальным и ожидаемым для функции генератора. При вызове в цикле for он просто завершает цикл.
@Boris «ниже этого» не очень точен, потому что с изменением оценки каждого ответа они могут повышаться или понижаться. Вы говорили об ответе Вики Лау?
@ Жан-Франсуа. "Ответ, который вы ищете, - это ответ Вики Ляу"
@Boris, стоит отметить, что ваше решение не хранит генераторы в качестве генераторов - l = [None, *l, None] распаковывает l в список. Исходное решение сохраняет генераторы как генераторы, что может быть тем, что вам нужно, например на память или побочные эффекты.
При работе с генераторами, где вам нужен какой-то контекст, я часто использую приведенную ниже служебную функцию, чтобы отобразить скользящее окно на итераторе:
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)
Если вы используете itertools, используйте вместо этого ответ Франсиско Кузо с itertools.tee: stackoverflow.com/a/41047005
Сразу предыдущий?
Вы имеете в виду следующее, правда?
previous = None
for item in someList:
if item == target: break
previous = item
# previous is the item before the target
Если вам нужны предыдущие элементы п, вы можете сделать это с помощью своего рода циклической очереди размером п.
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
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], это вернет тот же элемент, что и предыдущий элемент.
Проверьте утилиту петлителя из Проект Темпита. Он дает вам объект-оболочку вокруг элемента цикла, который предоставляет такие свойства, как предыдущий, следующий, первый, последний и т. д.
Взгляните на исходный код для класса лупера, это довольно просто. Существуют и другие такие помощники цикла, но я не могу вспомнить других прямо сейчас.
Пример:
> 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
Ссылки все битые.
Не очень питонический, но справляется и прост:
l=[1,2,3]
for index in range(len(l)):
if l[index]==2:
l[index-1]
ЧТО ДЕЛАТЬ: защитить края
Это точно так же, как ответ @Rudiger Wolf stackoverflow.com/a/324273
Я знаю, что это старый, но почему бы просто не использовать 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, ага, обновлю до версии, отвечающей требованиям.
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:]):
Я знаю, что это старый вопрос, но я считаю важным показать простое решение, которое также работает с генераторами и другими типами итераций, в отличие от большинства ответов, работающих только со списками, такими как объекты. Это несколько похоже на ответ Брайана и решение здесь: 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)
В этом случае я мог бы сделать «prev, item = item, next».