使用itertools.cycle()可以知道索引吗?

4
我需要循环遍历一个列表,当到达最后一个元素时返回到第一个元素。

可以使用itertools中的cycle对象来实现这个功能。

myList = [1,2,3,4,5,6,7,8,9]

i = 0
for item in cycle(myList):
    index = i%9
    print (index)
    i += 1

除了使用 i 变量外,还有其他方式吗?


你的索引似乎无法保持同步;你有一个9元素循环,但是在模10时进行了重置。 - DSM
2个回答

5
你可以使用 enumerate
for i, item in enumerate(cycle(myList)):

以下是示范内容:
>>> from itertools import cycle
>>> for i, item in enumerate(cycle([1, 2, 3])):
...     print i, item
...
0 1
1 2
2 3
3 1
4 2
5 3

您甚至可以指定一个特定的数字来开始:

for i, item in enumerate(cycle([1, 2, 3]), 10): # Start at 10

阅读@DSM的评论后,我意识到您可能希望交换对cycleenumerate的调用:
>>> for i, item in cycle(enumerate([1, 2, 3])):
...     print i, item
...
0 1
1 2
2 3
0 1
1 2
2 3

这将使i引用列表中item的索引,而不是作为计数器变量。


由于 % 10 的存在,我想知道 OP 是否真的想要类似 cycle(enumerate([1,2,3])) 这样的东西(带或不带 1 的起始值),以便列表的相同值始终对应于相同的索引。虽然很难确定。 - DSM

0
作为对此的扩展,我正在寻找一种方法来索引一个循环对象中的元素。
为此,您可以编写一个自定义类,并使用 `__getitem__` 方法替换 `cycle`。
from itertools import cycle, takewhile, dropwhile


class CyclicalList:
    def __init__(self, initial_list):
        self._initial_list = initial_list

    def __getitem__(self, item):
        if isinstance(item, slice):
            if item.stop is None:
                raise ValueError("Cannot slice without stop")
            iterable = enumerate(cycle(self._initial_list))
            if item.start:
                iterable = dropwhile(lambda x: x[0] < item.start, iterable)
            return [
                element
                for _, element in takewhile(lambda x: x[0] < item.stop, iterable)
            ]

        for index, element in enumerate(cycle(self._initial_list)):
            if index == item:
                return element

    def __iter__(self):
        return cycle(self._initial_list)

它使您能够使用常规的索引/片段表示法。

myList = CyclicalList([1,2,3,4,5,6,7,8,9])
myList[10]  # 2
myList[10:20]  # [2, 3, 4, 5, 6, 7, 8, 9, 1, 2]

你可能还想实现其他列表方法并根据需要进行优化。但这里讨论的是循环对象索引的主要思路。


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