Получение следующего элемента при циклическом просмотре списка - PullRequest
38 голосов
/ 30 января 2010
li = [0, 1, 2, 3]

running = True
while running:
    for elem in li:
        thiselem = elem
        nextelem = li[li.index(elem)+1]

Когда это достигает последнего элемента, вызывается IndexError (как в случае любого итерируемого списка, кортежа, словаря или строки).Я на самом деле хочу, чтобы в этот момент nextelem равнялось li[0].Мое довольно громоздкое решение этого вопроса было

while running:
    for elem in li:
        thiselem = elem
        nextelem = li[li.index(elem)-len(li)+1]   # negative index

Есть ли лучший способ сделать это?

Ответы [ 8 ]

71 голосов
/ 30 января 2010

Тщательно продумав это, я думаю, что это лучший способ. Он позволяет легко выйти в середину без использования break, что, на мой взгляд, важно, и требует минимальных вычислений, поэтому я считаю, что он самый быстрый Также не требуется, чтобы li был списком или кортежем. Это может быть любой итератор.

from itertools import cycle

li = [0, 1, 2, 3]

running = True
licycle = cycle(li)
# Prime the pump
nextelem = next(licycle)
while running:
    thiselem, nextelem = nextelem, next(licycle)

Я оставляю здесь другие решения для потомков.

Все эти причудливые итераторы имеют свое место, но не здесь. Используйте оператор%.

li = [0, 1, 2, 3]

running = True
while running:
    for idx, elem in enumerate(li):
        thiselem = elem
        nextelem = li[(idx + 1) % len(li)]

Теперь, если вы намереваетесь бесконечно циклически проходить по списку, просто сделайте это:

li = [0, 1, 2, 3]

running = True
idx = 0
while running:
    thiselem = li[idx]
    idx = (idx + 1) % len(li)
    nextelem = li[idx]

Я думаю, что это легче понять, чем другое решение, связанное с tee, и, вероятно, также быстрее. Если вы уверены, что размер списка не изменится, вы можете спрятать копию len(li) и использовать ее.

Это также позволяет вам легко сойти с колеса обозрения в середине, вместо того, чтобы ждать, пока ковш снова не опустится на дно. Другие решения (включая ваше) требуют, чтобы вы отметили running в середине цикла for, а затем break.

13 голосов
/ 30 января 2010
while running:
    for elem,next_elem in zip(li, li[1:]+[li[0]]):
        ...
7 голосов
/ 30 января 2010

Вы можете использовать попарно циклический итератор:

from itertools import izip, cycle, tee

def pairwise(seq):
    a, b = tee(seq)
    next(b)
    return izip(a, b)

for elem, next_elem in pairwise(cycle(li)):
    ...
5 голосов
/ 13 мая 2015

Используйте метод zip в Python. Эта функция возвращает список кортежей, где i-й кортеж содержит i-й элемент из каждой последовательности аргументов или итераций

    while running:
        for thiselem,nextelem in zip(li, li[1 : ] + li[ : 1]):
            #Do whatever you want with thiselem and nextelem         
3 голосов
/ 15 июля 2014

Довольно другой способ решить эту проблему:

   li = [0,1,2,3]

   for i in range(len(li)):

       if i < len(li)-1:

           # until end is reached
           print 'this', li[i]
           print 'next', li[i+1]

       else:

           # end
           print 'this', li[i]
3 голосов
/ 30 января 2010
while running:
    lenli = len(li)
    for i, elem in enumerate(li):
        thiselem = elem
        nextelem = li[(i+1)%lenli]
0 голосов
/ 06 сентября 2016
        li = [0, 1, 2, 3]
        for elem in li:
            if (li.index(elem))+1 != len(li):
                thiselem = elem
                nextelem = li[li.index(elem)+1]
                print 'thiselem',thiselem
                print 'nextel',nextelem
            else:
                print 'thiselem',li[li.index(elem)]
                print 'nextel',li[li.index(elem)]
0 голосов
/ 06 июля 2016
c = [ 1, 2, 3, 4 ]

i = int(raw_input(">"))

if i < 4:
    print i + 1
else:
    print -1
...