473,604 Members | 2,632 Online

# Rotating lists?

I need to transform this:

[1,2,3]

into this:

[2,3,1]

(a left-rotation. Actually, any rotation will do).

I tried:

a = a[1:] + a[0]

which doesn't work because there's no __add__ between a list and
integer, and:

a = a[1:].append(a[0])

but it doesn't work, since append returns None :( Right now, I'm doing
it with a temporary variable and it looks ugly - is there an elegant way
of doing it?

Jul 18 '05 #1
9 9185
[Ivan Voras]
I need to transform this:

[1,2,3]

into this:

[2,3,1]

(a left-rotation. Actually, any rotation will do).

For Py2.4, use collections.deq ue.rotate().

For earlier Pythons, concatenate list slices: a[1:] + a[:1]

Raymond Hettinger
Jul 18 '05 #2
Ivan Voras wrote:
I need to transform this:
[1,2,3]
into this:
[2,3,1]

Right now, I'm doing
it with a temporary variable and it looks ugly - is there an elegant way
of doing it?

l = range(1, 4)
l [1, 2, 3] import itertools
list(itertools. islice(itertool s.cycle(l), 1, len(l)+1))

[2, 3, 1]

That is, build an iterator that cycles over l indefinitely,
then take a slice of it starting x items in (where x==1 in
this case) and continuing until you've retrieved a number
of elements equal to the length of the original sequence.

-Peter
Jul 18 '05 #3
Ivan Voras wrote:
I need to transform this:

[1,2,3]

into this:

[2,3,1]

(a left-rotation. Actually, any rotation will do).

I tried:

a = a[1:] + a[0]

which doesn't work because there's no __add__ between a list and
integer, and:

a = a[1:].append(a[0])

but it doesn't work, since append returns None :( Right now, I'm doing
it with a temporary variable and it looks ugly - is there an elegant way
of doing it?

This smells like a use-case for itertools.cycle :
import itertools
c=itertools.cyc le( [1,2,3] )
c.next() 1 c.next() 2 c.next() 3 c.next() 1 c.next()

2

.... or is this not what you need to rotate your lists for?

--Irmen de Jong

Jul 18 '05 #4
Ivan Voras <ivoras@__-geri.cc.fer.hr> writes:
I tried:

a = a[1:] + a[0]

which doesn't work because there's no __add__ between a list and
integer, and:

You meant to say

a = a[1:] + [a[0]]
Jul 18 '05 #5
* Ivan Voras (2004-09-16 00:10 +0200)
I need to transform this:

[1,2,3]

into this:

[2,3,1]

(a left-rotation. Actually, any rotation will do).

I tried:

a = a[1:] + a[0]

which doesn't work because there's no __add__ between a list and
integer, and:

a = a[1:].append(a[0])

but it doesn't work, since append returns None :( Right now, I'm doing
it with a temporary variable and it looks ugly - is there an elegant way
of doing it?

def rotate(seq,
offset):
""" shift seq to the left by offset, with the elements shifted off the
beginning inserted back at the end """
return seq[offset:] + seq[:offset]
Jul 18 '05 #6
Thorsten Kampe wrote:

def rotate(seq,
offset):
""" shift seq to the left by offset, with the elements shifted off the
beginning inserted back at the end """
return seq[offset:] + seq[:offset]

You can also use a generator function:

def rotator(seq, offset=1):
while True:
yield seq
seq = seq[offset:] + seq[:offset]

T = rotator(range(5 ))
T.next()
[0, 1, 2, 3, 4]
T.next()
[1, 2, 3, 4, 0]
T.next()
[2, 3, 4, 0, 1]

You can rotate to the right using a negative offset:
L = rotator( range(5), -1 )
L.next()
[0, 1, 2, 3, 4]
L.next()
[4, 0, 1, 2, 3]
L.next()
[3, 4, 0, 1, 2]
Jul 18 '05 #7
Raymond Hettinger wrote:

For earlier Pythons, concatenate list slices: a[1:] + a[:1]

^^^^^

That's what I missed :) I should've thought of that :)
Thanks!
Jul 18 '05 #8
Irmen de Jong wrote:
This smells like a use-case for itertools.cycle :
>>> import itertools
>>> c=itertools.cyc le( [1,2,3] )
>>> c.next() 1 >>> c.next() 2 >>> c.next() 3 >>> c.next() 1 >>> c.next()

2

... or is this not what you need to rotate your lists for?

No, I don't need an (infinite) cycle, just the rotated list. But thanks,
I didn't notice itertools before :)
Jul 18 '05 #9
[Ivan Voras]> > a = a[1:] + a[0]

which doesn't work because there's no __add__ between a list and
integer, and:
[Paul Rubin]
You meant to say

a = a[1:] + [a[0]]

A better answer is a[1:] + a[:1] which nicely handles lists of length 0 and
length 1 as well as the OP's original example.

The advantage of using slices to extract a single element is that it avoids
IndexErrors for empty lists. This technique comes up often enough that I
thought it worth pointing out here.

Also worth mentioning is that slicing and concatenation are supported by several
sequence types. So, this operation can be abstracted to apply to more than just
lists.

It might also be opportune to point out the virtues of writing a few doctests
that would have surfaced the issues immediately.

Of course, Paul already knows this. This note is for the people who don't.
Raymond Hettinger
def rotate(seq):
""" Rotate the first element to the end of a sequence.

Returns a new sequence of the same type.
The type must support slicing and concatenation.
rotate(range(5) ) [1, 2, 3, 4, 0] rotate(range(1) ) [0] rotate(range(0) ) [] rotate('abc') 'bca' rotate('') '' rotate(tuple('a bc')) ('b', 'c', 'a') rotate(tuple('' ))

()
"""

return seq[1:] + seq[:1]

import doctest
doctest.testmod ()
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.