List rotation

M

M. Clift

Hi All,

Could someone help me out with this?

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')
items + 2 = ( 'c', 'd', 'a', 'b')
items + 3 = ( 'd', 'a', 'b', 'c')

trans = 1

list = ('a', 'd', 'b', 'a', 'd', 'c', 'b')

#and items = +1, the list would be;
#list = ('b', 'a', 'c', 'b', 'a', 'd', 'c') etc..

for idx in range(len(list)):
if trans == [1]:
list[idx] = [???]
print l1

Don't laugh, I'm a slow learner : )

Thanks,

M
 
S

Steven Bethard

M. Clift said:
Could someone help me out with this?

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')

Is it necessary to (ab)use the + syntax? If not, will this suffice:
.... return seq[n:] + seq[:n]
....
rotate(range(10), 1) [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
rotate(range(10), 2)
[2, 3, 4, 5, 6, 7, 8, 9, 0, 1]

You also might want to search google groups for more information. If I
understand your question right, this has been asked a number of times, for
example:

http://groups.google.com/groups?hl=en&lr=&ie=UTF-
8&safe=off&selm=3c4e7b1a.1031701568%40news.mch.sni.de
 
M

M. Clift

Hi Steven,

Sorry, as I'm a beginner I don't think I should have used the title rotate
list, as that's not what I want.

If the list ('a', 'd', 'b', 'a', 'd', 'c', 'b') was rotated once it would
of course give('d', 'b', 'a' etc...

What I'm looking for is that say if trans = 1, then the list would become
('b', 'a', 'c', 'b', 'a', 'd', 'c') .
For trans = 3 the list would be ('d', 'c', 'a', 'd', 'c', 'b', 'a')

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')
items + 2 = ( 'c', 'd', 'a', 'b')
items + 3 = ( 'd', 'a', 'b', 'c')

trans = 1

list = ('a', 'd', 'b', 'a', 'd', 'c', 'b')


I can think of the long/wrong way to do it as shown for trans = 3, but there
must be some simpler idea.


for idx in range(len(items)):
if list[idx:idx + 1] == ['a']:
list[idx:idx + 1] = ['d']
if list[idx:idx + 1] == ['b']:
list[idx:idx + 1] = ['a']
 
M

M. Clift

Hi Steven,

Sorry, as I'm a beginner I don't think I should have used the title rotate
list, as that's not what I want.

If the list ('a', 'd', 'b', 'a', 'd', 'c', 'b') was rotated once it would
of course give('d', 'b', 'a' etc...

What I'm looking for is that say if trans = 1, then the list would become
('b', 'a', 'c', 'b', 'a', 'd', 'c') .
For trans = 3 the list would be ('d', 'c', 'a', 'd', 'c', 'b', 'a')

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')
items + 2 = ( 'c', 'd', 'a', 'b')
items + 3 = ( 'd', 'a', 'b', 'c')

trans = 1

list = ('a', 'd', 'b', 'a', 'd', 'c', 'b')


I can think of the long/wrong way to do it as shown for trans = 3, but there
must be some simpler idea.


for idx in range(len(items)):
if list[idx:idx + 1] == ['a']:
list[idx:idx + 1] = ['d']
if list[idx:idx + 1] == ['b']:
list[idx:idx + 1] = ['a']
 
M

M. Clift

Hi Steven,

Sorry, as I'm a beginner I don't think I should have used the title rotate
list, as that's not what I want.

If the list ('a', 'd', 'b', 'a', 'd', 'c', 'b') was rotated once it would
of course give('d', 'b', 'a' etc...

What I'm looking for is that say if trans = 1, then the list would become
('b', 'a', 'c', 'b', 'a', 'd', 'c') .
For trans = 3 the list would be ('d', 'c', 'a', 'd', 'c', 'b', 'a')

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')
items + 2 = ( 'c', 'd', 'a', 'b')
items + 3 = ( 'd', 'a', 'b', 'c')

trans = 1

list = ('a', 'd', 'b', 'a', 'd', 'c', 'b')


I can think of the long/wrong way to do it as shown for trans = 3, but there
must be some simpler idea.


for idx in range(len(items)):
if list[idx:idx + 1] == ['a']:
list[idx:idx + 1] = ['d']
if list[idx:idx + 1] == ['b']:
list[idx:idx + 1] = ['a']
 
M

M. Clift

Hi Steven,

Sorry, as I'm a beginner I don't think I should have used the title rotate
list, as that's not what I want.

If the list ('a', 'd', 'b', 'a', 'd', 'c', 'b') was rotated once it would
of course give('d', 'b', 'a' etc...

What I'm looking for is that say if trans = 1, then the list would become
('b', 'a', 'c', 'b', 'a', 'd', 'c') .
For trans = 3 the list would be ('d', 'c', 'a', 'd', 'c', 'b', 'a')

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')
items + 2 = ( 'c', 'd', 'a', 'b')
items + 3 = ( 'd', 'a', 'b', 'c')

trans = 1

list = ('a', 'd', 'b', 'a', 'd', 'c', 'b')


I can think of the long/wrong way to do it as shown for trans = 3, but there
must be some simpler idea.


for idx in range(len(items)):
if list[idx:idx + 1] == ['a']:
list[idx:idx + 1] = ['d']
if list[idx:idx + 1] == ['b']:
list[idx:idx + 1] = ['a']
 
M

Michael Hoffman

M. Clift said:
If the list ('a', 'd', 'b', 'a', 'd', 'c', 'b') was rotated once it would
of course give('d', 'b', 'a' etc...

Yes. That is usually what people refer to as list rotation.
What I'm looking for is that say if trans = 1, then the list would become
('b', 'a', 'c', 'b', 'a', 'd', 'c') .

It took me a second to figure out what you want. You want to increase
the characters' ordinal values by one along some rotated list:

adbadcb
bacbadc

so for trans=1, a->b, b->c, c->d, d->a. If I got that correct, than you
want something like this:

"""
def rotate_letters(items, trans=1, rotation="abcd"):
"""
alphabet can be a string or a list
"""
return [rotation[(rotation.index(item)+trans) % len(rotation)]
for item in items]

print rotate_letters("abcd")
print rotate_letters(('a', 'd', 'b', 'a', 'd', 'c', 'b'))
print rotate_letters(('a', 'd', 'b', 'a', 'd', 'c', 'b'), trans=3)
"""

which gives the output

"""
['b', 'c', 'd', 'a']
['b', 'a', 'c', 'b', 'a', 'd', 'c']
['d', 'c', 'a', 'd', 'c', 'b', 'a']
"""

and will throw IndexError if you give it input that's not in the
rotation alphabet.

For more efficiency, you'd want to precompute the result for each
character in the rotation alphabet and store the result in a translation
table to be used by str.translate(). That's left as an exercise to the
user. ;)
 
P

Peter Otten

M. Clift said:
If the list ('a', 'd', 'b', 'a', 'd', 'c', 'b') was rotated once it would
of course give('d', 'b', 'a' etc...

What I'm looking for is that say if trans = 1, then the list would become
('b', 'a', 'c', 'b', 'a', 'd', 'c') .
For trans = 3 the list would be ('d', 'c', 'a', 'd', 'c', 'b', 'a')

def make_trans(items, n):
return dict(zip(items, items[n:] + items[:n]))

def transform(items, trans):
return [trans[item] for item in items]

for i in range(4):
print "N =", i, transform("adbadcb", make_trans("abcd", i))

Is that it?

Peter
 
R

Remco Boerma

Hi,
> ('b', 'a', 'c', 'b', 'a', 'd', 'c') .
> For trans = 3 the list would be ('d', 'c', 'a', 'd', 'c', 'b', 'a')
>
> items = ('a', 'b', 'c', 'd')
> items + 1 = ( 'b', 'c', 'd', 'a')
> items + 2 = ( 'c', 'd', 'a', 'b')
> items + 3 = ( 'd', 'a', 'b', 'c')

Is this what you're looking for?
>>> items = [1,2,3,4,5,6]
>>> items.append(items.pop(0))
>>> items [2, 3, 4, 5, 6, 1]
>>> items.append(items.pop(0))
>>> items [3, 4, 5, 6, 1, 2]
>>>

or, with the trans variable used:
>>> trans=3
>>> items = [1,2,3,4,5,6]
>>> for t in xrange(trans):
.... items.append(items.pop(0))
....
>>> items [4, 5, 6, 1, 2, 3]
>>>


M. Clift said:
for idx in range(len(items)):
if list[idx:idx + 1] == ['a']:
list[idx:idx + 1] = ['d']
if list[idx:idx + 1] == ['b']:
list[idx:idx + 1] = ['a']
That doesn't seem like a good option to me. .
 
S

Sion Arrowsmith

M. Clift said:
I can think of the long/wrong way to do it as shown for trans = 3, but there
must be some simpler idea.


for idx in range(len(items)):
if list[idx:idx + 1] == ['a']:
list[idx:idx + 1] = ['d']
if list[idx:idx + 1] == ['b']:
list[idx:idx + 1] = ['a']

Depending on what the possible characters are, you might be able
to do something with chr() and ord() and modulo arithmetic:

c2 = chr((ord(c1) - ord('a') + n) % 4 + ord('a'))

but Peter Otten's solution is more general.
 
P

Peter Abel

M. Clift said:
Hi Steven,

Sorry, as I'm a beginner I don't think I should have used the title rotate
list, as that's not what I want.

If the list ('a', 'd', 'b', 'a', 'd', 'c', 'b') was rotated once it would
of course give('d', 'b', 'a' etc...

What I'm looking for is that say if trans = 1, then the list would become
('b', 'a', 'c', 'b', 'a', 'd', 'c') .
For trans = 3 the list would be ('d', 'c', 'a', 'd', 'c', 'b', 'a')

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')
items + 2 = ( 'c', 'd', 'a', 'b')
items + 3 = ( 'd', 'a', 'b', 'c')

trans = 1

list = ('a', 'd', 'b', 'a', 'd', 'c', 'b')


I can think of the long/wrong way to do it as shown for trans = 3, but there
must be some simpler idea.


for idx in range(len(items)):
if list[idx:idx + 1] == ['a']:
list[idx:idx + 1] = ['d']
if list[idx:idx + 1] == ['b']:
list[idx:idx + 1] = ['a']


I'm not quite sure if I understood you well, but let me
try to explain what I mean to have understood:
myList=['A', 'B', 'C', 'D', 'E', 'F', 'G']
myList ['A', 'B', 'C', 'D', 'E', 'F', 'G']
# This is the myList in reverse order
myList.reverse()
myList ['G', 'F', 'E', 'D', 'C', 'B', 'A']
# But I think that's not what you want, so we reverse it back
myList.reverse()
myList
['A', 'B', 'C', 'D', 'E', 'F', 'G']
.... """ aList : the list to rotate (!! a list and not a tuple)
.... trans : the number of steps to rotate
.... direction: =1 rotate it backward,
.... means put items from the end to the front
.... =0 rotate it forward
.... """
.... if type(aList) != list:
.... print 'I need a list, you gave me a %s' % str(type(aList))
.... return
.... if direction:
.... # rotate it backwards
.... while trans>0:
.... aList.insert(0,aList.pop())
.... trans-=1
.... else:
.... while trans>0:
.... aList.append(aList.pop(0))
.... trans-=1
....
myList ['A', 'B', 'C', 'D', 'E', 'F', 'G']
rotateList(myList,3)
myList ['E', 'F', 'G', 'A', 'B', 'C', 'D']
rotateList(myList,3,direction=0)
myList ['A', 'B', 'C', 'D', 'E', 'F', 'G']

Some bad examples:
BTW some remarks:
Doen't use the word *list* for a name, it's reserved.
Use List, myList, anyList or l or anything else.
For this task I wouldn't use tuples, cause they are imutable.
If you have a sequence with many items, you would need much memory space.
This is the reason why I didn't create a new list and give
it back with return but work on the given list.
The list.methodes *insert*, *pop*, *reverse*, *append* and some
others are working on the given list and doen't create a new one.

Hope I could help you a bit.

Regards
Peter
 
M

M. Clift

Hi ,

I must say thankyou to all of you who have helped with this.

They translate the lists fine as I have explained so far, but there are some
problems with the list that I use. I did not explain that what I'm trying to
do is transpose a melody for fear of those of you who do not know music
theory not being able to give me valuable advice (That is if I had explained
all the possibilities - I thought that I had, but didn't ) .

As I said in the lists I have shown so far the transpose works. The problem
is is that a melody could be say ['C', 'E', 'B', 'F'], which should
transpose in the key of G to ['G', 'B', 'F#', 'D'] or in the key of F to
['F', 'A', 'E', 'Bb']

I now have something to work with and again thankyou to all, but if anyone
who understands a bit about music could offer any help I would be grateful.
I thought about trying to explain the problem further for non musicians, but
after I considered the possibility of double shaps and flats I thought it
best to not pester anyone.

Malcolm
 
M

M. Clift

Hi,

I think this might nearly be it;

Chords = ['C','Db','E','Gc','Ab']

def rotate_letters(items, trans=0, rotation=['C','Cb','Cc','D','Db','Dc',\
'E','Eb','Ec','F','Fb','Fc',\
'G','Gb','Gc','A','Ab','Ac',\
'B','Bb','Bc']):

return [rotation[(rotation.index(item)+trans) % len(rotation)]
for item in items]

print TUNE
print rotate_letters((Chords), trans=2)

The problem is this gives;

['Cc', 'E', 'Ec', 'Ab', 'B']

Fine you say, thats what you asked for. What it should read is;

['D', 'Eb','F','Ac','Bb']

So the first capital letters need to transpose, but not the second lower
case.

Any ideas?

For the musicians amoungst you the lower case refers to the inversion. i.e.
none = root, b = first and c of course = second

Thanks,

Malcolm
 
M

M. Clift

Hi,

Stop the press! Sorry, thats just me being dumb. Of course the easy way is
just to alter the trans value. So instead of trans = 1, trans should = 3 to
transpose the chords up a tone.

Also, to quote the Meaning of Life death/dinner party scene I have commited
social death in my last post.
Amoungst should of course be amongst, oh the shame of it.

Thanks,

Malcolm
 
J

Jeremy Bowers

Hi All,

Could someone help me out with this?

items = ('a', 'b', 'c', 'd')
items + 1 = ( 'b', 'c', 'd', 'a')
items + 2 = ( 'c', 'd', 'a', 'b')
items + 3 = ( 'd', 'a', 'b', 'c')

I keep seeing this come up and waiting for someone to post this answer,
which is what I think I would use. It happens to nearly work like you
wrote, too, though I actually had this idea formulated before your post:

----------------

class Rotater(object):
"""Rotater takes a sequence of fixed length (__len__ is
defined) that uses __getitem__ from 0 to len - 1, and translates
accesses such that the resulting list appears rotated, without
building any new lists.

Usage examples:
>>> l = ['a', 'b', 'c', 'd', 'e']
>>> r = Rotater(l) # No initial translation
>>> r[0] == 'a' True
>>> r[-1] == 'e' True
>>> r += 1 # translate by one more
>>> r[0] == 'b' True
>>> r[-1] == 'a' True
>>> list(r) == ['b', 'c', 'd', 'e', 'a'] True
>>> r += 9 # can go beyond one rotation
>>> list(r) == l True
>>> r -= 11 # can use negative rotation
>>> list(r) ['e', 'a', 'b', 'c', 'd']
>>> list(r+1) ['a', 'b', 'c', 'd', 'e']
>>> list(r-1) ['d', 'e', 'a', 'b', 'c']
>>> list(1+r)
['a', 'b', 'c', 'd', 'e']
"""

def __init__(self, wrapped, offset = 0):
self.wrapped = wrapped
self.offset = offset

def __getitem__(self, index):
index += self.offset
index %= len(self.wrapped)
return self.wrapped[index]

def __iadd__(self, offset):
self.offset += offset
return self

def __isub__(self, offset):
self.offset -= offset
return self

def __add__(self, offset):
return Rotater(self.wrapped, self.offset + offset)
def __sub__(self, offset):
return Rotater(self.wrapped, self.offset - offset)
def __radd__(self, offset):
return Rotater(self.wrapped, self.offset + offset)

def __iter__(self):
for i in range(len(self.wrapped)):
yield self

if __name__ == "__main__":
import sys
import doctest
doctest.testmod(sys.modules[__name__])

------------

This wins big for large lists that are rotated a lot by not constructing
extra lists. Note changes to the underlying lists are reflected in the
rotations, which can be a feature or a mis-feature depending on the
problem. In the small, it can be more convenient to work with than the
other solutions... or not, again depending on the problem.
 
D

Dennis Lee Bieber

For the musicians amoungst you the lower case refers to the inversion. i.e.
none = root, b = first and c of course = second
Pardon? You prior post discussed transposing the KEY of a piece.

This one is talking about chord inversions... But so far as I
know, a "C in 1st inversion" is /still/ a C chord -- instead of "CEG"
one is playing "EGC".

It is also confusing as, in the absence of musical notation, "b"
is often used to represent a "flat".

Assuming a key transposition, my take is:

-=-=-=-=-=-=-=-=-=-=-=-=-

# The following table should be expanded to include all the
accidentals
# that may occur... The key "C" needs C#/Db, D#, F#/Gb, G#/Ab, and A#
# and the others need the relevant mapping (which could lead to double
# sharps or double flats to make each key list the same length

# Note: I tried to derive the circle of keys from memory, may be
# some mistakes in the system

# MAJOR KEY arrangement
# half-steps 2 2 1 2 2 2 1
Keys = { "C" : ["C", "D", "E", "F", "G", "A", "B"], # no # or b
"G" : ["G", "A", "B", "C", "D", "E", "F#"], # one #
"D" : ["D", "E", "F#", "G", "A", "B", "C#"], # two #
"A" : ["A", "B", "C#", "D", "E", "F#", "G#"], # three #
"E" : ["E", "F#", "G#", "A", "B", "C#", "D#"], # four #
"B" : ["B", "C#", "D#", "E", "F#", "G#", "A#"], # five #
"F#" : ["F#", "G#", "A#", "B", "C#", "D#", "E#"], # six #
"C#" : ["C#", "D#", "E#", "F#", "G#", "A#", "B#"], #same notes
as "Db"
"F" : ["F", "G", "A", "Bb", "C", "D", "E"], # one b
"Bb" : ["Bb", "C", "D", "Eb", "F", "G", "A"], # two b
"Eb" : ["Eb", "F", "G", "Ab", "Bb", "C", "D"], # three b
"Ab" : ["Ab", "Bb", "C", "Db", "Eb", "F", "G"], # four b
"Db" : ["Db", "Eb", "F", "Gb", "Ab", "Bb", "C"], # five b
"Gb" : ["Gb", "Ab", "Bb", "Cb", "Db", "Eb", "F"], # six b
"Cb" : ["Cb", "Db", "Eb", "Fb", "Gb", "Ab", "Bb"], #same notes
as "B"
}

def Transpose(in_key, out_key, notes):
in_key = in_key[0].upper() + in_key[1:]
if Keys.has_key(in_key):
in_notes = Keys[in_key]
else:
raise "Invalid Key Signature", in_key
# Yes, it's a deprecated string exception!

out_key = out_key[0].upper() + out_key[1:]
if Keys.has_key(out_key):
out_notes = Keys[out_key]
else:
raise "Invalid Key Signature", out_key

out_list = []

for n in notes.split():
n = n[0].upper() + n[1:]
if n in in_notes:
out_list.append(out_notes[in_notes.index(n)])
else:
out_list.append("<'%s' invalid note>" % n)

return " ".join(out_list)


while 1:
print "\n"
print "For minor keys, enter the relative major key\n"

inkey = raw_input("Enter the starting key> ")
if not inkey: break

outkey = raw_input("Enter the output key> ")
if not outkey: break

print "\nEnter base chord/note sequence (separated by spaces)"
print "DO NOT enter maj, min, 7th, sus, etc. modifiers"
inchords = raw_input("Notes> ")
if not inchords: break

print Transpose(inkey, outkey, inchords)

-=-=-=-=-=-=-=-=-=-=-

From your prior post
As I said in the lists I have shown so far the transpose works. The problem
is is that a melody could be say ['C', 'E', 'B', 'F'], which should
transpose in the key of G to ['G', 'B', 'F#', 'D'] or in the key of F to
['F', 'A', 'E', 'Bb']

Hmmm, one of us has a mistake on the key of G

F:\Mail Attachments>python transpose.py


For minor keys, enter the relative major key

Enter the starting key> c
Enter the output key> g

Enter base chord/note sequence (separated by spaces)
DO NOT enter maj, min, 7th, sus, etc. modifiers
Notes> c e b f
G B F# C


For minor keys, enter the relative major key

Enter the starting key> c
Enter the output key> f

Enter base chord/note sequence (separated by spaces)
DO NOT enter maj, min, 7th, sus, etc. modifiers
Notes> c e b f
F A E Bb


For minor keys, enter the relative major key

Enter the starting key>

F:\Mail Attachments>


--
 
M

M. Clift

Hi Dennis,

In my effort to not confuse non musicians in my earlier posts I just used
letters, and then perhaps didn't explain fully how I crossed over to key
transposition.

Yes I agree using my method for inversions is a bit strange, I'm sure I had
a reason for it, but it's late here and for now I can't remember what it was
at the time : )

Thankyou for your code. Key transposition is what I was after. I appreciate
it.

Malcolm
 
M

M. Clift

Hi Dennis,

So much for it being late here. I just had to look over your code before I
go to bed. Excellent stuff, just what was needed : )

Can I ask are you writing a python music app? Just curious, as there doesn't
seem to be many around.

Malcolm
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top