说我有一个范围:
r = range(1, 6)
使用这个范围,我想无限循环并产生数字:
for i in cycle(r):
yield(i)
这将正确产生以下值:
1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, ...
但是,我有时想从特定值开始屈服,但继续使用定义的范围。也就是说,如果我想从3
开始,那么序列将是:
3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, ...
有没有办法通过range
和cycle
(或其他方式)的组合来实现这一目标?
答案 0 :(得分:3)
只需dropwhile
,直到达到要发出的第一个值:
>>> from itertools import cycle, dropwhile
>>> iterable = dropwhile(lambda x: x < 3, cycle(range(1, 6)))
>>> for _ in range(10):
... print(next(iterable))
...
3
4
5
1
2
3
4
5
1
2
根据文档(强调我的):
创建一个迭代器,只要在迭代器中删除元素 谓词是真的; 之后,返回每个元素。
predicate
仅在其评估false-y的第一个值生效。
答案 1 :(得分:2)
另一种方法是将两个范围链接在一起并将链传递给cycle
。
from itertools import cycle, chain
def shift_cycle(lo, start, stop):
return cycle(chain(range(start, stop), range(lo, start)))
for t in zip(range(12), shift_cycle(1, 3, 6)):
print('{}: {}'.format(*t))
<强>输出强>
0: 3
1: 4
2: 5
3: 1
4: 2
5: 3
6: 4
7: 5
8: 1
9: 2
10: 3
11: 4
如果islice
和dropwhile
args较大,则此方法优于start
或stop
,因为它不需要丢弃不需要的初始项。< / p>
答案 2 :(得分:1)
由于cycle
从赋予它的迭代器的开头开始,给它一个迭代器(在这种情况下是一个序列),它从你想要的地方开始:
r = tuple(range(3,6)) + tuple(range(1,3))
上面的1
是要重复的最低值,6
比最高值多一个,而3
使用两次是起始值。应该清楚如何将此概括为其他情况。
答案 3 :(得分:1)
sys.maxsize
出于多种目的“实际上是无限的”
import sys
r, n = 5, 3
cyc = (i%r + 1 for i in range(n, sys.maxsize))
next(cyc)
Out[106]: 4
next(cyc)
Out[107]: 5
next(cyc)
Out[108]: 1
next(cyc)
Out[109]: 2
next(cyc)
Out[110]: 3
next(cyc)
Out[111]: 4
next(cyc)
Out[112]: 5
next(cyc)
Out[113]: 1
sys.maxsize*1e-9/3600/24/365
Out[117]: 292.471208677536
每个请求的年数为1 ns - 在64位系统上
但当然运行速度有点慢
timeit.timeit('next(cyc)','r, n = 5, 3; cyc = (i%r + 1 for i in range(n, sys.maxsize))')
Out[126]: 0.2556792100261305
随着请求不断提升i
但这似乎不是下沉的重要时刻
timeit.timeit('max%5', 'max=sys.maxsize')
Out[120]: 0.07545763840474251
timeit.timeit('1111%5')
Out[122]: 0.01156394737682831
timeit.timeit('111%5')
Out[123]: 0.011720469965638358
答案 4 :(得分:0)
您正在寻找islice
功能
from itertools import islice, cycle
offset = 2
r = range(1, 6)
generator = islice(cycle(r), offset, None)