Cycle through list starting at a certain element
Solution 1
Look at itertools module. It provides all the necessary functionality.
from itertools import cycle, islice, dropwhile
L = [1, 2, 3, 4]
cycled = cycle(L) # cycle thorugh the list 'L'
skipped = dropwhile(lambda x: x != 4, cycled) # drop the values until x==4
sliced = islice(skipped, None, 10) # take the first 10 values
result = list(sliced) # create a list from iterator
print(result)
Output:
[4, 1, 2, 3, 4, 1, 2, 3, 4, 1]
Solution 2
Use the arithmetic mod
operator. Suppose you're starting from position k
, then k
should be updated like this:
k = (k + 1) % len(l)
If you want to start from a certain element, not index, you can always look it up like k = l.index(x)
where x is the desired item.
Solution 3
I'm not such a big fan of importing modules when you can do things by your own in a couple of lines. Here's my solution without imports:
def cycle(my_list, start_at=None):
start_at = 0 if start_at is None else my_list.index(start_at)
while True:
yield my_list[start_at]
start_at = (start_at + 1) % len(my_list)
This will return an (infinite) iterator looping your list. To get the next element in the cycle you must use the next
statement:
>>> it1 = cycle([101,102,103,104])
>>> next(it1), next(it1), next(it1), next(it1), next(it1)
(101, 102, 103, 104, 101) # and so on ...
>>> it1 = cycle([101,102,103,104], start_at=103)
>>> next(it1), next(it1), next(it1), next(it1), next(it1)
(103, 104, 101, 102, 103) # and so on ...
Solution 4
import itertools as it
l = [1, 2, 3, 4]
list(it.islice(it.dropwhile(lambda x: x != 4, it.cycle(l)), 10))
# returns: [4, 1, 2, 3, 4, 1, 2, 3, 4, 1]
so the iterator you want is:
it.dropwhile(lambda x: x != 4, it.cycle(l))
Comments
-
john almost 2 years
Say I have a list:
l = [1, 2, 3, 4]
And I want to cycle through it. Normally, it would do something like this,
1, 2, 3, 4, 1, 2, 3, 4, 1, 2...
I want to be able to start at a certain point in the cycle, not necessarily an index, but perhaps matching an element. Say I wanted to start at whatever element in the list
==4
, then the output would be,4, 1, 2, 3, 4, 1, 2, 3, 4, 1...
How can I accomplish this?
-
ovgolovin over 12 years@gnibbler It would take to put
4
in parenthesis(4).__cmp__
. Otherwise it doesn't work (at least in Python 2.7.2). And with parenthesis it doesn't look that beautiful. -
ovgolovin over 12 years@gnibbler And as of Python 3 it would take to use
__eq__
instead of__cmp__
(there is no__cmp__
as of the version 3). -
Duncan over 12 years@ovgolovin What @gnibbler wrote works without parentheses. Did you miss the space between
4
and.
? -
Duncan over 12 years@ovgolovin for Python 3 it should be
__ne__
or__gt__
rather than__eq__
. -
wim over 12 yearsspace between 4 and . ? what the heck is going on there?
-
ovgolovin over 12 years
itertools
is written inC
. So, it's quite fast apart from its eloquence. -
Duncan over 12 years@wim, if you write
4.__cmp__
Python will parse it as a floating point number4.
followed by an identifier__cmp__
and that's a syntax error.4 .__cmp__
on the other hand is the integer4
followed by a period to indicate an attribute reference and the attribute__cmp__
. -
stephanmg over 4 yearsI like this answer best.
-
busybear about 3 years
dropwhile
doesn't seem necessary here. You can instead uselist(islice(cycled, L.index(4), L.index(4) + 9))