7

Is there any way to create an iterator to repeat elements in a list certain times? For example, a list is given:

color = ['r', 'g', 'b']

Is there a way to create a iterator in form of itertools.repeatlist(color, 7) that can produce the following list?

color_list = ['r', 'g', 'b', 'r', 'g', 'b', 'r']
zhaodaolimeng
  • 626
  • 8
  • 11

2 Answers2

18

You can use itertools.cycle() together with itertools.islice() to build your repeatlist() function:

from itertools import cycle, islice

def repeatlist(it, count):
    return islice(cycle(it), count)

This returns a new iterator; call list() on it if you must have a list object.

Demo:

>>> from itertools import cycle, islice
>>> def repeatlist(it, count):
...     return islice(cycle(it), count)
...
>>> color = ['r', 'g', 'b']
>>> list(repeatlist(color, 7))
['r', 'g', 'b', 'r', 'g', 'b', 'r']
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

The documentation of cycle says:

Note, this member of the toolkit may require significant auxiliary storage (depending on the length of the iterable).

I'm curious why python doesn't provide a more efficient implementation:

def cycle(it):
    while True:
        for x in it:
            yield x

def repeatlist(it, count):
    return [x for (i, x) in zip(range(count), cycle(it))]

This way, you don't need to save a whole copy of the list. And it works if list is infinitely long.

youkaichao
  • 1,938
  • 1
  • 14
  • 26
  • 1
    Because `itertools.cycle` accepts an `iterable` which might be a generator that can only be generated through once, for example a `map` object. Once it's exhausted, you can't get element from it anymore. Thus your `cycle` will never reach `yield x` again, which makes it an infinite-loop. Try `print(*islice(cycle(map(int, "123")), 20))` – Escape0707 Aug 29 '20 at 09:45