从特定数字开始的范围内的无限循环

时间:2017-08-14 20:40:09

标签: python generator itertools

说我有一个范围:

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, ...

有没有办法通过rangecycle(或其他方式)的组合来实现这一目标?

5 个答案:

答案 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

如果islicedropwhile args较大,则此方法优于startstop,因为它不需要丢弃不需要的初始项。< / 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)