Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 251
Sierra Kilo Avatar asked Feb 25 '17 17:02

Sierra Kilo


People also ask

How does Itertools cycle work?

There's an easy way to generate this sequence with the itertools. cycle() function. This function takes an iterable inputs as an argument and returns an infinite iterator over the values in inputs that returns to the beginning once the end of inputs is reached.

What does cycle function from Itertools module do?

The cycle() function accepts an iterable and generates an iterator, which contains all of the iterable's elements. In addition to these elements, it contains a copy of each element.

What should you keep in mind when using the repeat () function of the Itertools module?

In repeat() we give the data and give the number, how many times the data will be repeated. If we will not specify the number, it will repeat infinite times. In repeat(), the memory space is not created for every variable.

What does the count () Itertool do?

itertools. count() makes an iterator that returns values that counts up or down infinitely. By default, it starts at 0 and increases by 1 . You can specify the starting value with the first argument start and the increment with the second argument step .


2 Answers

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:

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.

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.

like image 169
Martijn Pieters Avatar answered Sep 20 '22 00:09

Martijn Pieters


You can use itertools.islice for that:

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

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:

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.

like image 34
Willem Van Onsem Avatar answered Sep 21 '22 00:09

Willem Van Onsem