Cycle around a sequence
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Wed Feb 8 22:55:30 EST 2012
On Wed, 08 Feb 2012 01:10:28 +0000, Mark Lawrence wrote:
> I'm looking at a way of cycling around a sequence i.e. starting at some
> given location in the middle of a sequence and running to the end before
> coming back to the beginning and running to the start place.
If you have a sequence, and don't mind copying it, the easiest way is
just to slice and join:
>>> a = range(20)
>>> b = a[5:] + a[:5]
>>> print b
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4]
Short, sweet, easy and simple. What's not to like about it?
For small (say, less than a few thousand of items) sequences, this
probably is the fastest way to do it.
Handling this lazily is trickier than it seems, because you have to store
the first N items somewhere until you get to the rest of the iterable.
There is no Right Way to do it, since the best solution will depend on
how many items you have and how large N is.
Here's one way with itertools:
>>> from itertools import islice, chain, tee
>>> a = iter(range(20))
>>> t1, t2 = tee(a)
>>> b = chain(islice(t1, 5, None), islice(t2, None, 5))
>>> print list(b)
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4]
But read the docs for tee first: it may be that converting to a list is
faster and more memory efficient.
http://docs.python.org/library/itertools.html#itertools.tee
Using tee may be overkill. Here's a simpler way:
>>> a = iter(range(20))
>>> t = list(islice(a, 5))
>>> b = chain(a, t)
>>> list(b)
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4]
If your data is truly humongous, already stored in a list, and you don't
want to make a copy, then I recommend your trick of generating the
indexes:
def cycle(seq, n):
for indexes in (xrange(n, len(seq)), xrange(n)):
for i in indexes:
yield seq[i]
If your data is humongous but only available lazily, buy more memory :)
--
Steven
More information about the Python-list
mailing list