在循环列表时获取下一个元素

74
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

有没有更好的方法来做这个?


考虑省略 while 循环。它似乎与问题无关。如果它是相关的,请考虑解释原因。 - Jason R. Coombs
我想要无限循环遍历一个列表,因此使用while/for循环组合。抱歉,之前没有解释清楚。 - ignoramus
我假设你也希望能够在循环过程中停止,而不仅仅是在结束时停止? - Omnifarious
是的,我确定我可以使用 break 来实现。 - ignoramus
12个回答

119

我经过认真思考后,认为这是最好的方法。它可以让您在中途轻松跳出,而不使用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)的副本并使用它。

这还可以让你在中间轻松地离开旋转木马,而不必等待桶再次到达底部。其他解决方案(包括您的)需要在for循环的中间检查running,然后使用break


1
+1没错,这也很简单有效。对于那些可以使用极其简单的过程式解决方案的问题来说,没有必要使用这些不必要的复杂的函数式解决方案。Python不是一种函数式语言! - Mark Byers
在Python 3中,使用next(licycle)代替licycle.next() - Sam
1
喜欢这个!(idx + 1) % len(li) - Jonathan
不重置“running”为False吗? - Acebone
@Acebone - 我没有包含它,因为原帖只指定了他们想要那种标志,但没有给出任何逻辑来说明何时设置它。显然,在循环的某个地方将该标志设置为false将导致循环退出。 - Omnifarious
显示剩余5条评论

21
while running:
    for elem,next_elem in zip(li, li[1:]+[li[0]]):
        ...

1
这是我第二喜欢的,仅次于我的。 :-) 简单最好,但如果列表很大,这会创建两个副本。 - Omnifarious
2
我见过的最具Python风格的事情之一。 - Vincent Alex

7
你可以使用成对循环迭代器:
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)):
    ...

这很好。它将while循环和for循环合并为一个简洁的循环,该循环持续迭代列表中相邻的一对,并在末尾环绕。 - Jason R. Coombs
+1 是使用 pairwise - 一个非官方的库函数,它只存在于 itertools 的文档中。因此,虽然你无法导入它,但它已被证明是有效的。 - Jason R. Coombs
我认为在for循环内部模糊测试并要求使用break并不是一个好主意。 - Omnifarious

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

由于某种原因,这会将列表的第一个元素与最后一个元素再次打印出来。 - Avi Thour

6
使用Python中的zip方法。该函数返回一个元组列表,其中第i个元组包含来自每个参数序列或可迭代对象的第i个元素。
    while running:
        for thiselem,nextelem in zip(li, li[1 : ] + li[ : 1]):
            #Do whatever you want with thiselem and nextelem         

那真是太聪明了! - SteveJ
请注意,这将创建一个新列表;当处理大型列表时,可能不是您想要做的事情。 - aguadopd

6
一种解决方法如下:
   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]

1
就这么简单:
li = [0, 1, 2, 3]
while 1:
   for i, item in enumerate(x):
      k = i + 1 if i != len(x) - 1 else 0
      print('Current index {} : {}'.format(i,li[k]))

1
简单的解决方法是通过包含以下条件来删除IndexError错误:
if(index<(len(li)-1))

现在不会出现“索引超出范围”的错误,因为最后一个索引不会被访问到。想法是在迭代时访问下一个元素。当到达倒数第二个元素时,可以访问最后一个元素。
使用enumerate方法将索引或计数器添加到可迭代对象(列表、元组等)中。现在使用index+1,我们可以在遍历列表时访问下一个元素。
li = [0, 1, 2, 3]

running = True
while running:
    for index, elem in enumerate(li):
        if(index<(len(li)-1)):
            thiselem = elem
            nextelem = li[index+1]

1
这是一个伟大而简洁的解决方案。 - marty331

0
        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
   while running:
        lenli = len(li)
        for i, elem in enumerate(li):
            thiselem = elem
            nextelem = li[(i+1)%lenli] # This line is vital

2
你好,欢迎来到stackoverflow。请提供解释而不仅仅是代码作为你的答案。 - Roim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接