Reputation: 11
I'm somewhat familiar with built in "enumerate" function in python. I understand that if I have a list like this:
list = [A, B, C, D]
That enumerate will number it like this:
list = [(A,0), (B,1), (C,2), (D,3)]
Is there a way to enumerate starting with a different list item? For example starting from C rather than A?
list = [(A,2),(B,3),(C,0),(D,1)]
Alternatively, is there an even better way than using enumerate to do this?
What I'm attempting is to write program where the user would select the root note/key of a song, and the program would return which notes are in chords for that scale. For example a major chord is the first third and fifth notes in a scale. So in the key of C its C-E-G. I thought the best approach would be to enumerate a list of musical keys and print the first, third, fifth, items etc.
Upvotes: 1
Views: 614
Reputation: 180481
from itertools import cycle, islice, chain
def rolled(start,lst):
cycled = cycle(range(len(lst)))
list(islice(cycled, None, start))
tail = islice(lst, start, len(lst))
head = islice(lst, start)
yield from zip(chain(head, tail), cycled)
In [59]: for ind,chord in rolled(2):
....: print(ind,chord)
....:
A 2
B 3
C 0
D 1
In [60]: list(rolled(2))
Out[60]: [('A', 2), ('B', 3), ('C', 0), ('D', 1)]
Couldn't figure out a nicer way to skip the first numbers from cycled but this should be one of the fastest solutions for a larger list.
You could use a loop to skip the elements but it looks a bit ugly:
def rolled(start,lst):
cycled = cycle(range(len(lst)))
for _ in islice(cycled, None, start):
pass
tail = islice(lst, start, len(lst))
head = islice(lst, start)
yield from zip(chain(head, tail), cycled)
Upvotes: 0
Reputation: 1
Assuming that you know a priori the index of the element you want as your start for the enumeration, here are two possibilities, one using lists and enumerate, one using numpy.
mylist = ['A', 'B', 'C', 'D']
for index, value in enumerate(mylist):
print(index, value)
(0, 'A')
(1, 'B')
(2, 'C')
(3, 'D')
To simply "wrap" the list starting at index 2:
varlist = mylist[2:]+mylist[:2]
for index, value in enumerate(varlist):
print(index, value)
(0, 'C')
(1, 'D')
(2, 'A')
(3, 'B')
Using Numpy:
import numpy as np
myarr = np.array(mylist)
rolled = np.roll(myarr, 2)
for index, value in enumerate(rolled):
print(index, value)
(0, 'C')
(1, 'D')
(2, 'A')
(3, 'B')
Upvotes: 0
Reputation: 6148
Might not be very elegant:
>>> list2 = [(j, i%4) for i, j in enumerate(list,2)]
>>> list2
[('A', 2), ('B', 3), ('C', 0), ('D', 1)]
Upvotes: 1
Reputation: 36442
First of all:
list(enumerate(["A", "B", "C", "D"])) == [(0,"A"), (1,"B"), (2,"C"), (3,"D")]
Then: enumerate
enumerates a list in the order it is. If you want to enumerate it in a different order, you'll need to reorder the list first:
["Elephant", "Ant", "Dog"]
will enumerate as
print list(enumerate(["Elephant", "Ant", "Dog"]))
[(0, 'Elephant'), (1, 'Ant'), (2, 'Dog')]
however
print list(enumerate(sorted(["Elephant", "Ant", "Dog"])))
[(0, 'Ant'), (1, 'Dog'), (2, 'Elephant')]
will first sort the list alphabetically and then enumerate it.
Upvotes: 0
Reputation: 63757
enumerate out of the box won't wrap over the index if it exceeds the length of the iterable even though you start with an offset. Saying that it is trivial enough to extend the wrap over feature by a simple wrapper
for index, elem in ((index % len(lst), elem) for index, elem in enumerate(lst,2)):
print (index, elem)
(2, 'A')
(3, 'B')
(0, 'C')
(1, 'D')
And a wrapper is encouraged if you would be using in multiple times
enumerate_wrap = lambda it, offset: ((index % len(it), elem)
for index, elem in enumerate(it, offset))
for index, elem in enumerate_wrap(lst, 2):
print (index, elem)
(2, 'A')
(3, 'B')
(0, 'C')
(1, 'D')
Upvotes: 3