23

I'm looking for some code improvement, or a pre-built version of what I've implemented myself as I think there might be, or should be, a cleaner way to achieve what I want.

I'm writing a piece of software to convert guitar tabs into classical notation, I need to convert the number on a tab to it's corresponding note and it would be useful for building a list of each strings note from the starting string.

I have a list of notes, (a - g#) and a list of frets (0, 21).

Notes[fret] works fine for the first eleven notes but after that I obviously get an out of index error.

The code I have to get around this is here:

notes = ["a", "a#", "b", "c", "c#", "d", "e", "f", "f#", "g", "g#"]
note = 21
while note >= len(notes):
    note -= 11
    try:
        print notes[note]
    except:
        continue

It works but it seems a little long, is there a better way to do this?

double-beep
  • 5,031
  • 17
  • 33
  • 41
DasSnipez
  • 2,182
  • 4
  • 20
  • 29
  • 1
    Aren't you forgetting "d#" ? If so, using '%' like "notes[note % len(notes)]" is a good way to go, as it'll automatically correct for changing list sizes. – J-L Sep 25 '17 at 15:18

3 Answers3

44

Use the % operator to produce a modulus:

notes[note % len(notes)]

Demo:

>>> notes = ["a", "a#", "b", "c", "c#", "d", "e", "f", "f#", "g", "g#"]
>>> note = 21
>>> notes[note % len(notes)]
'g#'

or in a loop:

>>> for note in range(22):
...     print notes[note % len(notes)],
... 
a a# b c c# d e f f# g g# a a# b c c# d e f f# g g#
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
5

Another options is to use itertools.cycle

>>> import itertools
>>> notes = ["a", "a#", "b", "c", "c#", "d", "e", "f", "f#", "g", "g#"]

>>> frets = range(21)
>>> for note, fret in itertools.izip(itertools.cycle(notes), frets):
        print ("[%s, %d]" %(note, fret))

[a, 0]
[a#, 1]
[b, 2]
[c, 3]
[c#, 4]
[d, 5]
[e, 6]
[f, 7]
[f#, 8]
[g, 9]
[g#, 10]
[a, 11]
[a#, 12]
[b, 13]
[c, 14]
[c#, 15]
[d, 16]
[e, 17]
[f, 18]
[f#, 19]
[g, 20]
smac89
  • 39,374
  • 15
  • 132
  • 179
3

Use the modulo operator:

In [3]: notes = ["a", "a#", "b", "c", "c#", "d", "e", "f", "f#", "g", "g#"]

In [4]: len(notes)
Out[4]: 11

In [5]: note = 11

In [6]: notes[note]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-6-707e7e351463> in <module>()
----> 1 notes[note]

IndexError: list index out of range

In [7]: notes[note%len(notes)]
Out[7]: 'a'

In [8]: notes[note-11]
Out[8]: 'a'
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241