从特定元素开始循环遍历列表

25

假设我有一个列表:

l = [1, 2, 3, 4]

我希望您能循环访问它。通常情况下,它会执行以下操作:

1, 2, 3, 4, 1, 2, 3, 4, 1, 2...

我希望能够在循环中的某个特定点开始,不一定是按索引,而是可能匹配一个元素。比如说,如果我想从列表中任何一个等于4的元素开始,那么输出将是:

4, 1, 2, 3, 4, 1, 2, 3, 4, 1...

我该如何完成这个任务?

7个回答

28

看看 itertools 模块。它提供了所有必要的功能。

from itertools import cycle, islice, dropwhile

L = [1, 2, 3, 4]

cycled = cycle(L)  # cycle thorugh the list 'L'
skipped = dropwhile(lambda x: x != 4, cycled)  # drop the values until x==4
sliced = islice(skipped, None, 10)  # take the first 10 values

result = list(sliced)  # create a list from iterator
print(result)

输出:

[4, 1, 2, 3, 4, 1, 2, 3, 4, 1]

1
dropwhile doesn't seem necessary here. You can instead use list(islice(cycled, L.index(4), L.index(4) + 9)) - busybear

20

使用算术模运算符mod。假设你从位置k开始,那么k应该像这样更新:

k = (k + 1) % len(l)
如果你想要从特定元素开始,而不是索引,你可以像这样查找它:k = l.index(x)其中x是所需的项目。

5
我不是特别喜欢在可以用几行代码解决的情况下引入模块。以下是我没有引入任何模块的解决方案:
def cycle(my_list, start_at=None):
    start_at = 0 if start_at is None else my_list.index(start_at)
    while True:
        yield my_list[start_at]
        start_at = (start_at + 1) % len(my_list)

这将返回一个(无限)循环您的列表的迭代器。要获取循环中的下一个元素,您必须使用next语句:
>>> it1 = cycle([101,102,103,104])
>>> next(it1), next(it1), next(it1), next(it1), next(it1)
(101, 102, 103, 104, 101) # and so on ...
>>> it1 = cycle([101,102,103,104], start_at=103)
>>> next(it1), next(it1), next(it1), next(it1), next(it1)
(103, 104, 101, 102, 103) # and so on ...

6
itertools 是用 C 编写的,因此除了其优雅之外,它相当快速。 - ovgolovin
2
我最喜欢这个答案。 - stephanmg

2
import itertools as it
l = [1, 2, 3, 4]
list(it.islice(it.dropwhile(lambda x: x != 4, it.cycle(l)),  10))
# returns: [4, 1, 2, 3, 4, 1, 2, 3, 4, 1]

所需的迭代器是:

it.dropwhile(lambda x: x != 4, it.cycle(l))

@gnibbler,需要将4放在括号中(4).__cmp__。否则它不起作用(至少在Python 2.7.2中是这样)。而且加上括号看起来也不太美观。 - ovgolovin
@gnibbler而且,从Python 3开始,需要使用__eq__而不是__cmp__(在版本3中没有__cmp__)。 - ovgolovin
@ovgolovin,@gnibbler所写的代码不需要用括号。你是不是忘记在 4. 之间加上空格了? - Duncan
对于Python 3来说,应该是__ne__或者__gt__而不是__eq__。@ovgolovin - Duncan
2
4 和 . 之间的空格?那里到底发生了什么事? - wim
8
如果你写 4.__cmp__,Python会将其解析为浮点数 4. 后跟一个标识符 __cmp__,这是语法错误。另一方面,4 .__cmp__ 是整数 4,后跟一个句点表示属性引用和属性 __cmp__ - Duncan

1

另一个奇怪的选项是可以反向循环列表。例如:

# Run this once
myList = ['foo', 'bar', 'baz', 'boom']
myItem = 'baz'

# Run this repeatedly to cycle through the list
if myItem in myList:
    myItem = myList[myList.index(myItem)-1]
    print myItem

1

1

可以使用类似这样的东西:

def my_cycle(data, start=None):
  k = 0 if not start else start
  while True:
    yield data[k]
    k = (k + 1) % len(data)

然后运行:

for val in my_cycle([0,1,2,3], 2):
  print(val)

本质上与之前的答案相同。我的错。


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