Sierra Kilo
Sierra Kilo

Reputation: 275

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.

Upvotes: 11

Views: 4284

Answers (3)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476709

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.

Upvotes: 4

Martijn Pieters
Martijn Pieters

Reputation: 1122232

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.

Upvotes: 13

Kasravnd
Kasravnd

Reputation: 107297

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

Upvotes: 0

Related Questions