Cycle through lists based on different list? - python

I want to cycle through my first list c based on my second list changes.
What I would like to see as a result is:
60, 71, 62, 69, 64, 71, 64, 67.
Currently, it just prints the list c. My real list for changes has 64 numbers in total.
For context the list c is the midi values for the C maj scale.
How can I achieve this? I'm sure it's simple.
C = [60, 62, 64, 65, 67, 69, 71]
changes = [0, 6, 2, 4, 4, 4, 3, 2]
for notes in C:
print(notes)

Try:
C = [60, 62, 64, 65, 67, 69, 71]
changes = [0, 6, 2, 4, 4, 4, 3, 2]
output = []
idx_current = 0
for x in changes:
idx_current = (idx_current + x) % len(C)
output.append(C[idx_current])
print(output) # [60, 71, 62, 69, 64, 71, 64, 67]
Based on your output, I guess you want to increase the index of C while wrapping around if necessary. This is done in the line idx = (idx + d) % len(C), i.e., increase the index modulo len(C).
Alternatively, using Assignment expression for Python 3.8+, you can do (with the same idea)
idx_cur = 0
idx = [idx_cur := (idx_cur + x) % len(C) for x in changes]
output = [C[i] for i in idx]

Related

in python language create several variables in a loop and after append items in each ones

I'm trying to find a way to append items in variables created on the fly
c = ('a','b','g','d','j')
p = 2
for r in c:
globals()['ssvar%s' % r] = []
for z in range (0,10,1):
for r in c:
p = p + 2
(['ssvar%s' % r]).append (p)
print ssvara #result >>> []
print ssvarb #result >>> []
print ssvarg #result >>> []
print ssvard #result >>> []
print ssvarj #result >>> []
but the expression (['ssvar%s' % poire]).append doesn't work.
can you direct me to the same topic or tell me how to vary the variable name to be fill ?
Don't do this, but I think what you were looking to do is
c = ('a','b','g','d','j')
p = 2
for r in c:
globals()['ssvar%s' % r] = []
for z in range (0, 10, 1):
for r in c:
p = p + 2
globals()['ssvar%s' % r].append(p)
Instead, you can create your own dictionary (container of key: value pairs) and store the lists in there as values and use the keys as names. If this dictionary is called my_dict, then my_dict['ssvara'] references the list corresponding to 'ssvara', my_dict['ssvarb'] references the list corresponding to 'ssvarb' and so on.
c = ('a','b','g','d','j')
p = 2
my_dict = {}
for r in c:
my_dict['ssvar%s' % r] = []
for z in range (0, 10, 1):
for r in c:
p = p + 2
my_dict['ssvar%s' % r].append(p)
print my_dict
Output
{'ssvara': [4, 14, 24, 34, 44, 54, 64, 74, 84, 94],
'ssvarb': [6, 16, 26, 36, 46, 56, 66, 76, 86, 96],
'ssvard': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
'ssvarg': [8, 18, 28, 38, 48, 58, 68, 78, 88, 98],
'ssvarj': [12, 22, 32, 42, 52, 62, 72, 82, 92, 102]}
If the actual names are not important (you are, after all, creating them dynamically), you can just create a list of lists. If this list is called my_list, my_list[0] references the first sublist, my_list[1] references the second, and so on.
c = ('a','b','g','d','j')
p = 2
my_list = [[] for i in range(len(c))]
for z in range (0, 10, 1):
for l in my_list:
p = p + 2
l.append(p)
print my_list
Output
[[4, 14, 24, 34, 44, 54, 64, 74, 84, 94],
[6, 16, 26, 36, 46, 56, 66, 76, 86, 96],
[8, 18, 28, 38, 48, 58, 68, 78, 88, 98],
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
[12, 22, 32, 42, 52, 62, 72, 82, 92, 102]]
I don't use Python 2 so I had to make a few interpolations.
I try to create temporaly variables with multiple items inside.
in fact I need to have, for exemple, this result:
ssvara
>>>> ['4','6','8','10','12','14','16', '8','20','22']
ssvara
>>>> ['24','26','28','30','32','34','36', '38','40','42']
the value of p is not important, the main thing is to be able to append. even with a local variable.

how can I sort array with np.sort()

I have A = np.array([43, 66, 34, 55, 78, 105, 2])
I need to sort the A[i] by increase if number is divisible by 2
Answer will be array([ 43, 2, 34, 55, 66, 105, 78])
How can I do this using np.sort()?
You could use boolean indexing and set sorted values in place:
idx = A % 2 == 0
A[idx] = np.sort(A[idx])

How can I evenly sample an array in Python, in order, according to a sample rate?

I have array_large and array_small. I need to evenly sample from array_large so that I end up with an array the same size as array_small. (Or in other words, I need a representative, downsized version of array_large to match up with array_small.)
As a super-trivial example, if array_small = [0, 1] and array_large = [0, 1, 2, 3] I would expect sample = [0, 2] or sample = [1, 3].
Let's imagine array_small is 30 items and array_large is 100.
array_small = [i for i in range(30)]
array_large = [i for i in range(100)]
sample_rate = len(array_large) / len(array_small)
In that case our sample_rate is 3.333... which means we want about every 3rd item, but sometimes every 4th item. Since the sample_rate is a float we can account for that with math.floor() and use the mod operator on the array index:
import math
array_large_sample = [
num for i, num in enumerate(array_large)
if math.floor(i % sample_rate) == 0
]
print(array_large_sample)
print(len(array_large_sample))
OUTPUT:
[0, 4, 7, 11, 14, 17, 21, 24, 27, 31, 34, 37, 41, 44, 47, 51, 54, 57, 61, 64, 67, 71, 74, 77, 81, 84, 87, 91, 94, 97]
30

how to split a list into multiple lists with certain ranges?

I have a list that needs to be split into 4 separate lists with maximum size of 21 depending on the amount of items in the original list.
The master list can have from 1 to 84 items.
I want the items to start in a and fill up to a maximum of 21 in a, b, c, d
I have the following code that can split the items up no problem but I want to know if there is a shorter way to do this. I am repeating code a lot except the range.
codes = [x for x in range(80)] # range anywhere between 1-84
print(len(codes))
a = []
b = []
c = []
d = []
for i in range(0, 21):
try:
a.append(codes[i])
except IndexError:
pass
for i in range(21, 42):
try:
b.append(codes[i])
except IndexError:
pass
for i in range(42, 63):
try:
c.append(codes[i])
except IndexError:
pass
for i in range(63, 84):
try:
d.append(codes[i])
except IndexError:
pass
print(len(a), len(b), len(c), len(d))
print(a)
print(b)
print(c)
print(d)
Before that I had this code that works great for the whole 84 items as the order is not important..
a = []
b = []
c = []
d = []
for a1, b1, c1, d1 in zip(*[iter(codes)]*4):
a.append(a1)
b.append(b1)
c.append(c1)
d.append(d1)
However if i have say 4 items, it will add 1 to each
a = [0]
b = [1]
c = [2]
d = [3]
What I would like to obtain is
a = [0, 1, 2, 3]
b = []
c = []
d = []
You can simply use sublist
a = codes[0: 21]
b = codes[21:42]
c = codes[42:63]
d = codes[63:84]
This will be fine for your requirement
#SajalPreetSinghs answer is correct for a simple use case like OP's but it also has some disadvantages when it comes to scalability.
For example:
When you need 20 sublists instead of the actual 4. You would have to add 16 more lines and specify 2 different numbers per line each!
Now imagine you already extended the code to 20 sublists but now you want the maximum item count per sublist to be 37 instead of 21 - you would have to change 2*20 = 40 numbers!
Improved scalability with generators
So if you want something with a better scalability you could use the following code which makes usage of generators:
Code
def sublist(orig_list, list_of_subs, max_items_per_list):
def sublist_generator():
for sublist in list_of_subs:
yield sublist
sublist = sublist_generator()
current_sublist = next(sublist)
for element in orig_list:
current_sublist.append(element)
if len(current_sublist) == max_items_per_list: # current list is full
current_sublist = next(sublist) # so let current point to the next list
Setup and usage
import random
start = 1
stop = random.randint(2, 85) # generate random int inclusively 2 and 85
codes = [x for x in range(start, stop)] # stop is exclusive: range(1, 85) == [1, 2, ..., 84]
a, b, c, d = [], [], [], []
sublists = [a, b, c, d] # *1
sublist(codes, sublists, 21)
for sublist in sublists:
print(sublist)
Better scalability because
If you want to change the number of items per sublist you only have to pass in the new maximum number.
If you want to increase the number of sublists you only have to add more of them to the sublists variable which you pass to the function (see *1).
If you need this code more often it's no problem because you can comfortably call the function.
I hope this helps someone!
Cheers
winklerrr
You could use the zip_longest function from itertools
from itertools import zip_longest
master_list = range(0, 84)
iterables = [iter(master_list)] * 21
slices = zip_longest(*iterables, fillvalue=None)
for slice in slices:
print("slice", slice)
# slice (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
# slice (21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41)
# slice (42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62)
# slice (63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83)
You can do it with using a list comprehension:
MAX_SIZE = 21
l = list(range(80))
l1,l2,l3,l4 = [l[i*MAX_SIZE: (i+1)*MAX_SIZE] for i in range(4)]
#l1=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,20],
# ....
#l4=[63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
What I would do would be just put it in one loop.
if index is 0 to 83
for i in range(0,84):
if i>=0 and i<=20:
a.append(codes[i])
elif i>20 and i<=41:
b.append(codes[i])
elif i>41 and i<=62:
c.append(codes[i])
elif i>62 and i<=83:
d.append(codes[i])
A solution using a list comprehension:
i_list = range(0,84)
r = 21
res = [i_list[i:i+r] for i in range(0,len(i_list),r)]

How work unpacking in python? [duplicate]

Is it possible to simulate extended tuple unpacking in Python 2?
Specifically, I have a for loop:
for a, b, c in mylist:
which works fine when mylist is a list of tuples of size three. I want the same for loop to work if I pass in a list of size four.
I think I will end up using named tuples, but I was wondering if there is an easy way to write:
for a, b, c, *d in mylist:
so that d eats up any extra members.
You can't do that directly, but it isn't terribly difficult to write a utility function to do this:
>>> def unpack_list(a, b, c, *d):
... return a, b, c, d
...
>>> unpack_list(*range(100))
(0, 1, 2, (3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99))
You could apply it to your for loop like this:
for sub_list in mylist:
a, b, c, d = unpack_list(*sub_list)
You could define a wrapper function that converts your list to a four tuple. For example:
def wrapper(thelist):
for item in thelist:
yield(item[0], item[1], item[2], item[3:])
mylist = [(1,2,3,4), (5,6,7,8)]
for a, b, c, d in wrapper(mylist):
print a, b, c, d
The code prints:
1 2 3 (4,)
5 6 7 (8,)
For the heck of it, generalized to unpack any number of elements:
lst = [(1, 2, 3, 4, 5), (6, 7, 8), (9, 10, 11, 12)]
def unpack(seq, n=2):
for row in seq:
yield [e for e in row[:n]] + [row[n:]]
for a, rest in unpack(lst, 1):
pass
for a, b, rest in unpack(lst, 2):
pass
for a, b, c, rest in unpack(lst, 3):
pass
You can write a very basic function that has exactly the same functionality as the python3 extended unpack. Slightly verbose for legibility. Note that 'rest' is the position of where the asterisk would be (starting with first position 1, not 0)
def extended_unpack(seq, n=3, rest=3):
res = []; cur = 0
lrest = len(seq) - (n - 1) # length of 'rest' of sequence
while (cur < len(seq)):
if (cur != rest): # if I am not where I should leave the rest
res.append(seq[cur]) # append current element to result
else: # if I need to leave the rest
res.append(seq[cur : lrest + cur]) # leave the rest
cur = cur + lrest - 1 # current index movded to include rest
cur = cur + 1 # update current position
return(res)
Python 3 solution for those that landed here via an web search:
You can use itertools.zip_longest, like this:
from itertools import zip_longest
max_params = 4
lst = [1, 2, 3, 4]
a, b, c, d = next(zip(*zip_longest(lst, range(max_params))))
print(f'{a}, {b}, {c}, {d}') # 1, 2, 3, 4
lst = [1, 2, 3]
a, b, c, d = next(zip(*zip_longest(lst, range(max_params))))
print(f'{a}, {b}, {c}, {d}') # 1, 2, 3, None
For Python 2.x you can follow this answer.

Categories

Resources