[英]How to specify where to start in an itertools.cycle function
I need to cycle through a list for starting position between 1-4
using itertools
I am able to cycle through the list我需要使用itertools
循环浏览1-4
之间起始位置的列表我能够循环浏览列表
positions = itertools.cycle([1,2,3,4])
next(positions)
This does return the next position, but what if the next time I need to start at 3?这确实返回了下一个位置,但是如果下次我需要从 3 开始呢? How can I set the start position?如何设置起始位置?
I need the start position to change often, I cant just change the list to start at 3.我需要经常更改开始位置,我不能只是将列表更改为从 3 开始。
You can't set a starting position;你不能设置起始位置; it'll always start where the given sequence starts.它总是从给定序列开始的地方开始。
You can move the cycle along a few steps before you use it for whatever you need it for.您可以将循环向前移动几个步骤,然后再将其用于任何您需要的用途。 Use itertools.islice()
to skip some items:使用itertools.islice()
跳过一些项目:
from itertools import islice
starting_at_three = islice(positions, 2, None)
You pass in the iterable, then a start and stop value;您传入可迭代对象,然后是开始和停止值; None
here means that the islice()
iterator continues forever or until the underlying positions
iterator is exhausted.这里的None
意味着islice()
迭代器永远持续下去,或者直到底层positions
迭代器耗尽。
Demo:演示:
>>> from itertools import islice, cycle
>>> positions = cycle([1, 2, 3, 4])
>>> starting_at_three = islice(positions, 2, None)
>>> next(starting_at_three)
3
>>> next(starting_at_three)
4
>>> next(starting_at_three)
1
The other option is to pass in a different sequence;另一种选择是传入不同的序列; you could pass in [3, 4, 1, 2]
for example.例如,您可以传入[3, 4, 1, 2]
。
You can use itertools.islice
for that:您可以使用itertools.islice
:
from itertools import cycle
from itertools import islice
positions3 = islice(cycle([1,2,3,4]),2,None)
this will result in a generator that emits 3,4,1,2,3,4,1,2,3,4,...这将导致生成器发出 3,4,1,2,3,4,1,2,3,4,...
In case the start position k
is large (compared to the length of the original list), it can pay off to perform a modulo first:如果起始位置k
很大(与原始列表的长度相比),则可以先执行取模:
from itertools import cycle
from itertools import islice
source_list = [1,2,3,4]
k = 10000000 # offset index
positions_k = islice(cycle(source_list),k%len(source_list),None)
This will generate an equivalent result, but islice
will not drop the first 10M elements.这将生成等效的结果,但islice
不会删除前 10M 元素。
Use slices of the original list:使用原始列表的切片:
In [15]: def custom_slice(lst, start):
....: return cycle(lst[start:] + lst[:start + 1])
Demo:演示:
In [16]: positions = custom_slice(lst, 2)
In [17]: next(positions)
Out[17]: 3
In [18]: next(positions)
Out[18]: 4
In [19]: next(positions)
Out[19]: 1
In [20]: next(positions)
Out[20]: 2
You can do this with itertools.dropwhile .你可以用itertools.dropwhile做到这一点。 It will ignore values until the predicate function is satisfied, then continue iterating over the entire cycle.它将忽略值,直到满足谓词函数为止,然后在整个循环中继续迭代。
>>> c = itertools.cycle([1, 2, 3, 4, 5])
>>> dw = itertools.dropwhile(lambda x: x < 3, c)
>>> [next(dw) for _ in range(10)]
[3, 4, 5, 1, 2, 3, 4, 5, 1, 2]
However, as noted in the docs但是,如文档中所述
the iterator does not produce any output until the predicate first becomes false, so it may have a lengthy start-up time迭代器在谓词第一次变为假之前不会产生任何输出,因此它可能有很长的启动时间
So it's better to use islice
for this use case.所以最好在这个用例中使用islice
。
>>> timeit.timeit(setup='from itertools import cycle, islice',
stmt='c = cycle(range(1000)); sl = islice(c, 900, None); assert next(sl) == 900')
35.37439359538257
>>> timeit.timeit(setup='from itertools import cycle, dropwhile',
stmt='c = cycle(range(1000)); dw = dropwhile(lambda x: x < 900, c); assert next(dw) == 900')
131.17783254291862
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.