【发布时间】:2012-01-20 11:30:06
【问题描述】:
假设我有一个清单:
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...
我怎样才能做到这一点?
【问题讨论】:
假设我有一个清单:
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...
我怎样才能做到这一点?
【问题讨论】:
查看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]
【讨论】:
dropwhile 在这里似乎没有必要。你可以改用list(islice(cycled, L.index(4), L.index(4) + 9))
使用算术mod 运算符。假设您从位置k 开始,那么k 应该像这样更新:
k = (k + 1) % len(l)
如果你想从某个元素开始,而不是索引,你总是可以像 k = l.index(x) 一样查找它,其中 x 是所需的项目。
【讨论】:
当您只需几行代码就可以自己完成工作时,我不太喜欢导入模块。这是我没有导入的解决方案:
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 ...
【讨论】:
itertools 写成C。所以,除了口才,还是挺快的。
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))
【讨论】:
4 放在括号(4).__cmp__ 中。否则它不起作用(至少在 Python 2.7.2 中)。加上括号,它看起来并不那么漂亮。
__eq__ 而不是 __cmp__(在版本 3 中没有 __cmp__)。
4 和. 之间的空格吗?
4.__cmp__,Python 会将其解析为浮点数4.,后跟标识符__cmp__,这是语法错误。另一方面,4 .__cmp__ 是整数4,后跟一个句点,表示属性引用和属性__cmp__。
嗯,http://docs.python.org/library/itertools.html#itertools.cycle 没有这样的开始元素。
也许你只是开始循环并丢弃你不喜欢的第一个元素。
【讨论】:
另一个奇怪的选择是循环遍历列表可以向后完成。例如:
# 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
【讨论】:
可以这样使用:
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)
与之前的答案之一基本相同。我的错。
【讨论】: