Есть ли способ получить доступ к списку (или кортежу или другому повторимому) далее или предыдущему элементу во время цикла с циклом for?
l=[1,2,3]
for item in l:
if item==2:
get_previous(l,item)
Есть ли способ получить доступ к списку (или кортежу или другому повторимому) далее или предыдущему элементу во время цикла с циклом for?
l=[1,2,3]
for item in l:
if item==2:
get_previous(l,item)
Выражается как функция генератора:
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
Один простой способ.
l=[1,2,3]
for i,j in zip(l, l[1:]):
print i, j
l=[1,2,3]
for i,item in enumerate(l):
if item==2:
get_previous=l[i-1]
print get_previous
>>>1
Когда вы имеете дело с генераторами, в которых вам нужен какой-то контекст, я часто использую приведенную ниже функцию утилиты, чтобы получить скользящее окно на итераторе:
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)
Проверьте утилиту 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
Я знаю, что это старо, но почему бы просто не использовать 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
Если вы запустите это, вы увидите, что он захватывает предыдущие и следующие элементы и не заботится о повторении элементов в списке.
Я не думаю, что есть простой способ, особенно, что итерабель может быть генератором (не возвращаться). Там есть достойное обходное решение, полагающееся на явное пропускание индекса в тело цикла:
for itemIndex, item in enumerate(l):
if itemIndex>0:
previousItem = l[itemIndex-1]
else:
previousItem = None
Функция enumerate()
является встроенной.
Итераторы имеют только метод next(), поэтому вы не можете смотреть вперед или назад, вы можете получить только следующий элемент.
enumerate (iterable) может быть полезна, если вы повторяете список или кортеж.
Непосредственно предыдущий?
Вы имеете в виду следующее, верно?
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
Если вы хотите, чтобы решение работало над итерами, 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
Не очень pythonic, но делает это и прост:
l=[1,2,3]
for index in range(len(l)):
if l[index]==2:
l[index-1]
ДЕЛАТЬ: защитить края
Самый простой способ - найти список для элемента:
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]