Как получить доступ к предыдущему / следующему элементу во время цикла? - PullRequest
42 голосов
/ 27 ноября 2008

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

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

Ответы [ 12 ]

68 голосов
/ 27 ноября 2008

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

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
27 голосов
/ 08 мая 2014

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

l=[1,2,3]
for i,j in zip(l, l[1:]):
    print i, j
11 голосов
/ 27 ноября 2008
l=[1,2,3]
for i,item in enumerate(l):
    if item==2:
        get_previous=l[i-1]
        print get_previous

>>>1
7 голосов
/ 26 февраля 2014

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

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

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 голосов
/ 28 ноября 2008

Проверьте утилиту 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
2 голосов
/ 27 ноября 2008

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

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

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

1 голос
/ 08 декабря 2016

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

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

1 голос
/ 27 ноября 2008

Сразу предыдущий?

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

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
1 голос
/ 27 ноября 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...