Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #19996 > unrolled thread
| Started by | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| First post | 2012-02-08 01:10 +0000 |
| Last post | 2012-02-09 21:34 +1100 |
| Articles | 10 — 8 participants |
Back to article view | Back to comp.lang.python
Cycle around a sequence Mark Lawrence <breamoreboy@yahoo.co.uk> - 2012-02-08 01:10 +0000
Re: Cycle around a sequence Christoph Hansen <ch@radamanthys.de> - 2012-02-08 03:01 +0100
Re: Cycle around a sequence Neil Cerutti <neilc@norwich.edu> - 2012-02-08 14:25 +0000
Re: Cycle around a sequence Terry Reedy <tjreedy@udel.edu> - 2012-02-08 15:15 -0500
Re: Cycle around a sequence Mark Lawrence <breamoreboy@yahoo.co.uk> - 2012-02-08 22:47 +0000
Re: Cycle around a sequence Serhiy Storchaka <storchaka@gmail.com> - 2012-02-09 12:10 +0200
Re: Cycle around a sequence Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-02-09 03:55 +0000
Re: Cycle around a sequence Chris Angelico <rosuav@gmail.com> - 2012-02-09 15:16 +1100
Re: Cycle around a sequence Peter Otten <__peter__@web.de> - 2012-02-09 09:33 +0100
Re: Cycle around a sequence Chris Angelico <rosuav@gmail.com> - 2012-02-09 21:34 +1100
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2012-02-08 01:10 +0000 |
| Subject | Cycle around a sequence |
| Message-ID | <mailman.5525.1328663401.27778.python-list@python.org> |
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. About the best I could come up with is the following, any better ideas for some definition of better? PythonWin 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32. Portions Copyright 1994-2008 Mark Hammond - see 'Help/About PythonWin' for further copyright information. >>> from itertools import chain >>> a=range(10) >>> g = chain((a[i] for i in xrange(4, 10, 1)), (a[i] for i in xrange(4))) >>> for x in g: print x, ... 4 5 6 7 8 9 0 1 2 3 >>> -- Cheers. Mark Lawrence.
[toc] | [next] | [standalone]
| From | Christoph Hansen <ch@radamanthys.de> |
|---|---|
| Date | 2012-02-08 03:01 +0100 |
| Message-ID | <jgsl21$q0d$1@online.de> |
| In reply to | #19996 |
Mark Lawrence schrieb:
> 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. About the
> best I could come up with is the following, any better ideas for some
> definition of better?
# quick&dirty
seq=range(10)
for x in seq[4:]+seq[:4]:
print x
# or
def oneround(seq, start=0):
i=start
l=len(seq)
while True:
yield seq[i]
i = (i+1) % l
if i==start: break
for x in oneround(range(50), 4):
print x
[toc] | [prev] | [next] | [standalone]
| From | Neil Cerutti <neilc@norwich.edu> |
|---|---|
| Date | 2012-02-08 14:25 +0000 |
| Message-ID | <9pfeutFtjiU2@mid.individual.net> |
| In reply to | #19996 |
On 2012-02-08, Mark Lawrence <breamoreboy@yahoo.co.uk> 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. About the best I could come up with is the
> following, any better ideas for some definition of better?
Python's indices were designed for these kinds of shenanigans.
def rotated(seq, n):
"""Iterate through all of seq, but starting from index n.
>>> ", ".join(str(n) for n in rotated(range(5), 3))
'3, 4, 0, 1, 2'
"""
i = n - len(seq)
while i < n:
yield seq[i]
i += 1
if __name__ == "__main__":
import doctest
doctest.testmod()
If you have merely an iterable instead of a sequence, then look
to some of the other clever stuff already posted.
--
Neil Cerutti
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2012-02-08 15:15 -0500 |
| Message-ID | <mailman.5551.1328732195.27778.python-list@python.org> |
| In reply to | #20023 |
On 2/8/2012 9:25 AM, Neil Cerutti wrote:
> On 2012-02-08, Mark Lawrence<breamoreboy@yahoo.co.uk> 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. About the best I could come up with is the
>> following, any better ideas for some definition of better?
>
> Python's indices were designed for these kinds of shenanigans.
>
> def rotated(seq, n):
> """Iterate through all of seq, but starting from index n.
>
> >>> ", ".join(str(n) for n in rotated(range(5), 3))
> '3, 4, 0, 1, 2'
> """
>
> i = n - len(seq)
> while i< n:
> yield seq[i]
> i += 1
This is really nice, in the category of "Why didn't I think of that?"
(Probably because I knew the % mod solution from C and never 'updated'!)
> if __name__ == "__main__":
> import doctest
> doctest.testmod()
>
> If you have merely an iterable instead of a sequence, then look
> to some of the other clever stuff already posted.
To make a repeating rotator is only a slight adjustment:
k = n - len(seq)
while True:
i = k
while i < n:
yield seq[i]
i += 1
--
Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2012-02-08 22:47 +0000 |
| Message-ID | <mailman.5554.1328741236.27778.python-list@python.org> |
| In reply to | #20023 |
On 08/02/2012 14:25, Neil Cerutti wrote: > On 2012-02-08, Mark Lawrence<breamoreboy@yahoo.co.uk> 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. About the best I could come up with is the >> following, any better ideas for some definition of better? > > Python's indices were designed for these kinds of shenanigans. > > def rotated(seq, n): > """Iterate through all of seq, but starting from index n. > > >>> ", ".join(str(n) for n in rotated(range(5), 3)) > '3, 4, 0, 1, 2' > """ > > i = n - len(seq) > while i< n: > yield seq[i] > i += 1 > > if __name__ == "__main__": > import doctest > doctest.testmod() > > If you have merely an iterable instead of a sequence, then look > to some of the other clever stuff already posted. > The winner :) -- Cheers. Mark Lawrence.
[toc] | [prev] | [next] | [standalone]
| From | Serhiy Storchaka <storchaka@gmail.com> |
|---|---|
| Date | 2012-02-09 12:10 +0200 |
| Message-ID | <mailman.5577.1328782266.27778.python-list@python.org> |
| In reply to | #20023 |
08.02.12 22:15, Terry Reedy написав(ла):
> To make a repeating rotator is only a slight adjustment:
>
> k = n - len(seq)
> while True:
> i = k
> while i < n:
> yield seq[i]
> i += 1
for i in range(n, len(seq)):
yield seq[i]
while True:
for x in seq:
yield x
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-02-09 03:55 +0000 |
| Message-ID | <4f3343b2$0$1615$c3e8da3$76491128@news.astraweb.com> |
| In reply to | #19996 |
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
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2012-02-09 15:16 +1100 |
| Message-ID | <mailman.5564.1328761006.27778.python-list@python.org> |
| In reply to | #20044 |
On Thu, Feb 9, 2012 at 2:55 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > If your data is humongous but only available lazily, buy more memory :) Or if you have a huge iterable and only need a small index into it, snag those first few entries into a list, then yield everything else, then yield the saved ones: def cycle(seq,n): seq=iter(seq) lst=[next(seq) for i in range(n)] try: while True: yield next(seq) except StopIteration: for i in lst: yield i >>> list(cycle(range(10,20),2)) [12, 13, 14, 15, 16, 17, 18, 19, 10, 11] Requires storage space relative to n, regardless of the length of the iterator. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2012-02-09 09:33 +0100 |
| Message-ID | <mailman.5573.1328776409.27778.python-list@python.org> |
| In reply to | #20044 |
Chris Angelico wrote:
> On Thu, Feb 9, 2012 at 2:55 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> If your data is humongous but only available lazily, buy more memory :)
>
> Or if you have a huge iterable and only need a small index into it,
> snag those first few entries into a list, then yield everything else,
> then yield the saved ones:
> def cycle(seq,n):
> seq=iter(seq)
> lst=[next(seq) for i in range(n)]
> try:
> while True: yield next(seq)
> except StopIteration:
> for i in lst: yield i
I think that should be spelt
def cycle2(seq, n):
seq = iter(seq)
head = [next(seq) for i in range(n)]
for item in seq:
yield item
for item in head:
yield item
or, if you are into itertools,
def cycle3(seq, n):
seq = iter(seq)
return chain(seq, list(islice(seq, n)))
$ python -m timeit -s'from tmp import cycle; data = range(1000); start=10'
'for item in cycle(data, 10): pass'
1000 loops, best of 3: 358 usec per loop
$ python -m timeit -s'from tmp import cycle2; data = range(1000); start=10'
'for item in cycle2(data, 10): pass'
1000 loops, best of 3: 172 usec per loop
$ python -m timeit -s'from tmp import cycle3; data = range(1000); start=10'
'for item in cycle3(data, 10): pass'
10000 loops, best of 3: 56.5 usec per loop
For reference:
$ python -m timeit -s'data = range(1000); start=10' 'for item in
data[start:] + data[:start]: pass'
10000 loops, best of 3: 56.4 usec per loop
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2012-02-09 21:34 +1100 |
| Message-ID | <mailman.5578.1328783688.27778.python-list@python.org> |
| In reply to | #20044 |
On Thu, Feb 9, 2012 at 7:33 PM, Peter Otten <__peter__@web.de> wrote: > Chris Angelico wrote: > >> def cycle(seq,n): >> seq=iter(seq) >> lst=[next(seq) for i in range(n)] >> try: >> while True: yield next(seq) >> except StopIteration: >> for i in lst: yield i > > I think that should be spelt > > def cycle2(seq, n): > seq = iter(seq) > head = [next(seq) for i in range(n)] > for item in seq: > yield item > for item in head: > yield item Thanks, yeah, don't know what I was thinking :) Too much C work lately! ChrisA
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web