Cycle through list starting at a certain element

22,662

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))
Share:
22,662
john
Author by

john

I love adventure and puzzles.

Updated on July 09, 2022

Comments

  • john
    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
    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
    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
    Duncan over 12 years
    @ovgolovin What @gnibbler wrote works without parentheses. Did you miss the space between 4 and .?
  • Duncan
    Duncan over 12 years
    @ovgolovin for Python 3 it should be __ne__ or __gt__ rather than __eq__.
  • wim
    wim over 12 years
    space between 4 and . ? what the heck is going on there?
  • ovgolovin
    ovgolovin over 12 years
    itertools is written in C. So, it's quite fast apart from its eloquence.
  • Duncan
    Duncan over 12 years
    @wim, if you write 4.__cmp__ Python will parse it as a floating point number 4. followed by an identifier __cmp__ and that's a syntax error. 4 .__cmp__ on the other hand is the integer 4 followed by a period to indicate an attribute reference and the attribute __cmp__.
  • stephanmg
    stephanmg over 4 years
    I like this answer best.
  • busybear
    busybear about 3 years
    dropwhile doesn't seem necessary here. You can instead use list(islice(cycled, L.index(4), L.index(4) + 9))