How can I change the view of my list? - python

Good evening! I have the following code which works when you write
python new.py -s 13 -p 5 on the command prompt.
What command prompt prints is :
[[1, [0], [0]], [1, [0], [0]], [1, [0], [0]], [1, [0]], [1, [0]]]
But I wanted:
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0], [1, 0]]
How can I do this?
-s 12 is the length of the string and -p 7 the 1s.
Thank you!
My code sample :
import argparse
p = argparse.ArgumentParser()
p.add_argument("-pulses", help = "number of pulses", type = int)
p.add_argument("-slots", help = "length of the rythm", type = int)
args = p.parse_args()
slots = args.slots
pulses = args.pulses
pauses = slots - pulses
mod = slots % pulses
rhythm = []
if mod != 0:
i = 0
j = 0
temp = []
while i < pulses:
rhythm.append([1])
i = i + 1
while j < pauses:
rhythm.append([0])
j = j + 1
m = slots
n = pauses
while (rhythm[-1]==[0]):
if (n!=0):
step = m%n
hlp = n
m = n
n = step
i = 0
while (i<step):
rhythm[i].append(rhythm[-1])
rhythm.remove(rhythm[-1])
i = i + 1
print (rhythm)

Note: This is a mere copy&paste from the comment.
Check this out.
I haven't fully analyzed your code but I believe your problem resides in append(). Try to replace it for extend().

The Problem is this line
rhythm[i].append(rhythm[-1])
rhythm[-1] returns a list ([0] or [1]). So you must use extend instead of append.
rhythm[i].extend(rhythm[-1])
Python List

Woozy Coder definitively correctly answered this question.
More generally speaking about lists appending and extending:
dest_list.append(appended_item) appends an item to the list. Should the appended item be a list, this list will be appended as is, and becomes an additional item at the end of the destination list.
dest_list.extend(list_extension) extends a list with another list, every item of this other list being individually appended to the end of the destination list.

Your code seems overly complicated. I think the code below does what you're trying to do:
def rhythm_list(slots, pulses):
q, r = divmod(slots, pulses)
full = [1] + [0] * q
part = full[:-1]
return [full] * r + [part] * (pulses - r)
# Test
print(rhythm_list(13, 5))
print(rhythm_list(12, 7))
print(rhythm_list(12, 4))
output
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0], [1, 0]]
[[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [1], [1]]
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]
Note that the output list contains duplicated references to the full and part lists, so if you do:
m = rhythm_list(12, 7)
m[0][0]=2
then m becomes:
[[2, 0], [2, 0], [2, 0], [2, 0], [2, 0], [1], [1]]
If this behaviour is undesirable, then change the last line of rhythm_list to
return [full[:] for _ in range(r)] + [part[:] for _ in range(pulses - r)]

Related

Generating Numerical Permutations (Iteration vs Recursion)

I think I am trying to do something quite fundamental and quite simple. For this reason, I was sure Stack Overflow would already have a post regarding this task but I guess not? Maybe it is an inconsequential concept? Apologies if a post for this already exists. I couldn't find it.
Here is what I want to accomplish: Given a list length n and a maximum element value m, generate all of the permutations of the list with each element varying between 0 and m.
QUESTIONS: 1. Is there a way to do this recursively? 2. Is recursion optimal (in terms of computational resources, O time, etc.) for this concept or is iteration better? 3. Is there a better way (less complicated) to achieve this using iteration (see my code below)?
more information found below
I have edited my code and the two examples to produce and exhibit complete solutions
Here are two examples:
Example 1: n = 3, m = 2
Output:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 2, 0]
[0, 2, 1]
[0, 2, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
[1, 2, 0]
[1, 2, 1]
[1, 2, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 2]
[2, 1, 0]
[2, 1, 1]
[2, 1, 2]
[2, 2, 0]
[2, 2, 1]
[2, 2, 2]
Example 1: n = 2, m = 4
Output:
[0, 0]
[0, 1]
[0, 2]
[0, 3]
[0, 4]
[1, 0]
[1, 1]
[1, 2]
[1, 3]
[1, 4]
[2, 0]
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[3, 0]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[4, 0]
[4, 1]
[4, 2]
[4, 3]
[4, 4]
My intuition tells me this can be done recursively but I can't think of how to do it (I'm a beginner programmer). Currently, I have a solution to achieve this iteratively:
def permute(curr_permute,max_num,reset_flgs,reset_ind):
'''
Increment Logic Structure
'''
perm_ind = 0
max_val_flgs = [0]*len(curr_permute)
for c_i in range(len(curr_permute)):
if ((curr_permute[c_i] == max_num) and (c_i < (len(curr_permute)-1))):
if ((reset_ind == c_i) and (reset_flgs[c_i] == 1)):
reset_ind += 1
reset_flgs[c_i] = 0
max_val_flgs[c_i] = 1
continue
else:
perm_ind += 1
max_val_flgs[c_i] = 1
elif (c_i == (len(curr_permute)-1)):
if (curr_permute[c_i] == max_num):
perm_ind = c_i
max_val_flgs[c_i] = 1
else:
perm_ind = c_i
elif (curr_permute[c_i] < max_num):
perm_ind += 1
'''
Reverse the lists
'''
max_val_flgs.reverse()
curr_permute.reverse()
reset_flgs.reverse()
'''
Reset Logic Structure
'''
for n_i in range(len(curr_permute)):
if (max_val_flgs[n_i] == 0):
break
elif ((max_val_flgs[n_i] == 1) and (reset_flgs[n_i] == 1)):
curr_permute[n_i] = 0
perm_ind += -1
'''
Reverse the lists
'''
curr_permute.reverse()
reset_flgs.reverse()
'''
Apply the permutation increment
'''
curr_permute[perm_ind] += 1
return(curr_permute,reset_flgs,reset_ind)
def Permutation_Generation():
n = 2
m = 4
curr_permute = [0]*n
reset_flgs = [1]*n
reset_ind = 0
All_Permutations = [list(curr_permute)]
while (sum(curr_permute) < (n*m)):
print(curr_permute)
[curr_permute,reset_flgs,reset_ind] = permute(curr_permute,m,reset_flgs,reset_ind)
All_Permutations.append(list(curr_permute))
print(curr_permute)
return(All_Permutations)
Apologies for the garbage code. Once I came up with a way to do it successfully, I didn't make much effort to clean it up or make it more efficient. My guess is this code is too complicated for the concept I am attempting to address.
I don't think your output with n and m are 3, 2, respectively, really make sense. After 6th row [0, 2, 0], shouldn't it be followed by [0, 2, 1] instead of [1, 0, 0]? Same also happened after 13th row.
Anyway here is an recursive alterantive:
n = 3
m = 2
def permutation(n, m):
if n <= 0:
yield []
else:
for i in range(m+1):
for j in permutation(n-1, m):
yield [i] + j
# or even shorter
def permutation(n, m):
return [[i] + j for i in range(m + 1) for j in permutation(n - 1, m)] if n > 0 else []
for i in permutation(n, m):
print(i)
Output:
[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], ..., [2, 1, 0], [2, 1, 1], [2, 1, 2], [2, 2, 0], [2, 2, 1], [2, 2, 2]]
3. You want to get all permutations. The number of permutations given n and m is (m+1)^n.
Because you actually want to print all of them the time complexity is also O((m+1)^n), which is what you get when doing it iteratively.
1+2. I don't think you should use recursion to do it, O((m+1)^n) is the optimal time you can do it and it's what you get when using iterations. recursion will also take more memory for it's memory stack.
The question seems to be answered, but I want to contribute an alternative for the permutation by iteration that is a bit simpler. Here I use list comprehensions, formatted string literals (the f'string' strings) and the eval built-in method. Hope this perspective is helpful to you (somehow?).
def get_permutations_list(array_size, max_value):
'''Returns a list of arrays that represent all permutations between zero
and max_value'''
array_member =''
for_loops=''
#Does a loop iteration for each member of the permutation list template
for i in range(array_size):
#adds a new member in each permutation
array_member += f'x{i}, '
#adds a new corresponding for loop
for_loops+=" for x{i} in range({value})".format(i=i,
value=max_value)
output = f'[[{array_member}] {for_loops}]' #combines it all together
return eval(output)
a = get_permutations_list(array_size=2, max_value=2)
print(a)
#Result: [[0,0],[0,1],[1,0],[1,1]]

Why is append() not following the condition of the if statement?

This section of code is supposed to check if the neighboring points exist as part of the points list.
The points list is a given.
The check list is currently only checking the first item of the points list.
The counted list is supposed to show the points that exist within the points list that neighbor the first given point.
The rowNbr and colNbr are the following conditions of what points neighbor a given point.
points = [[3,2],[4,2],[4,3],[5,2],[5,3],[6,4]]
temp = [[3,2],[4,2],[4,3],[5,2],[5,3],[6,4]]
check = []
counted = []
rowNbr = [1, -1, 0, 0, 1, 1, -1, -1]
colNbr = [0, 0, 1, -1, 1, -1, 1, -1]
check.append(points[0])
for j in range(len(check)):
for i in range(len(rowNbr)):
temp[j][0] = check[j][0] + rowNbr[i]
temp[j][1] = check[j][1] + colNbr[i]
if temp[j] in points:
counted.append(temp[:])
print(counted)
I want it to print: [[4, 2], [4, 3]]
It prints out the following:
[[[2, 1], [4, 2], [4, 3], [5, 2], [5, 3], [6, 4]], [[2, 1], [4, 2], [4, 3], [5, 2], [5, 3], [6, 4]]]
If I include a print(temp[j]) line within the if temp[j] in points: loop, it prints the corect coordinates, but the counted list is wrong and printing out everything.
Why is this error occurring and how do I fix it?
counted.append(temp[:]) appends a copy of the whole temp array each time it is executed -- if you just want it to append a copy of temp[j], do counted.append(temp[j][:]) instead.
I think you are missing an element in the reference to temp[:] (should be counted.append(temp[j][:]) instead of counted.append(temp[:]):
points = [[3,2],[4,2],[4,3],[5,2],[5,3],[6,4]]
temp = [[3,2],[4,2],[4,3],[5,2],[5,3],[6,4]]
check = []
counted = []
rowNbr = [1, -1, 0, 0, 1, 1, -1, -1]
colNbr = [0, 0, 1, -1, 1, -1, 1, -1]
check.append(points[0])
for j in range(len(check)):
for i in range(len(rowNbr)):
temp[j][0] = check[j][0] + rowNbr[i]
temp[j][1] = check[j][1] + colNbr[i]
if temp[j] in points:
counted.append(temp[j][:])
print(counted)

Python Dilemma this function should be working but it doesn't

I think this should work but doesn't could someone explain me why? the function is expand and should behave as following, given a list of 0 and 1 as input:
if input = [1,0,1] -> output = [[0, 1], [1, 0], [0, 1]]
if input = [1,1,1] -> output = [[0, 1], [0, 1], [0, 1]]
if input = [0,1,1] -> output = [[1, 0], [0, 1], [0, 1]]
if input = [0,0,0] -> output = [[1, 0], [1, 0], [1, 0]]
ecc.
WHY THE FOLLOWING IS NOT WORKING?
def expand(a):
o = []
t = [0]*2 # t = [0,0]
for element in a:
if element == 0:
t[0] = 1
t[1] = 0
elif element == 1:
t[0] = 0
t[1] = 1
o.append(t)
return o
#Es using expand: input [1,0,1] -> output [[1, 0], [1, 0], [1, 0]]
#instead of [[0, 1], [1, 0], [0, 1]] what's wrong?
You should create t inside the for loop. Now t will always reflect the last time it is changed.
Look at t as a name for a certain piece of memory. Since you don't change the memory-location, you keep on adapting the same piece over and over again
for element in a:
t = [0]*2
if element == 0:
#rest of your code
Here the memory-location is changed, since you create t anew eachtime
Just don't use a temporary list and do it like this:
def expand(a):
o = []
for element in a:
if element == 0:
o.append([1, 0])
elif element == 1:
o.append([0, 1])
return o
Another solution would be a list comprehension:
def expand(a):
# if your input values can only be `1` or `0`
# 'if 0' always evaluates to False whereas 'if any_int_except_zero' always evaluates to True
return [[0, 1] if element else [1, 0] for element in a]

Map arrays to integers in python

I have an array [[0, 1, 1], [1, 0, 0], [1, 1, 0], [0, 1, 1], [1, 0, 0]] and I want to get this [[0], [1], [2], [0], [1]] - so I want to specify all the same vectors with unique number.
I have an idea how to do it, but it is really ugly, pretty slow and not pythonic at all. How could I do it more pythonic and nicer?
def get_multiclass_list_nodes(y_):
_class = 0
prev_list = list()
new_y = list()
for el in y_:
el = el.astype('int32').tolist()
if el in prev_list:
index = -1
for i, val in enumerate(prev_list):
if val == el:
index = i + 1
break
new_y.append([index])
else:
_class += 1
prev_list.append(el)
new_y.append([_class])
return np.array(new_y)
This should work for you:
def map_lists_to_ints(list_of_lists): # Name this better
tuples = (tuple(l) for l in list_of_lists)
seen = {}
next_int = 0
for tup in tuples:
if tup not in seen:
seen[tup] = next_int
next_int += 1
yield seen[tup]
list_of_lists = [[0, 1, 1], [1, 0, 0], [1, 1, 0], [0, 1, 1], [1, 0, 0]]
result = list(map_lists_to_ints(list_of_lists))
print(result)
listified_result = [[x] for x in result]
print(listified_result)
Output:
[0, 1, 2, 0, 1]
[[0], [1], [2], [0], [1]]
Maybe this is abusing numpy a bit, but an easy way:
a = np.array([[0, 1, 1], [1, 0, 0], [1, 1, 0], [0, 1, 1], [1, 0, 0]])
lst = [str(x) for x in a]
result = np.unique(lst, return_inverse=True)[1]
Perhaps you'll want to tweak the final result, but it's trivial from there.

Python list bug or am I wrong?

I have constructed a 3 level nested list
#run on Python 3.2.3 32 bit on Win 7
L2=list(0 for i in range(2))
L3=list(L2 for i in range(3))
L4=list(L3 for i in range(4))
#give a new value to the very first number in list:
L4[0][0][0]=5
print("L4:")
print(L4)
#outputs erronously:
#[[[5, 0], [5, 0], [5, 0]], [[5, 0], [5, 0], [5, 0]], [[5, 0], [5, 0], [5, 0]], [[5, 0], [5, 0], [5, 0]]]
The same list given explicitly
#the same L4 given explicitly:
anotherL4=[[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
print("anotherL4:")
#give a new value to the very first number:
anotherL4[0][0][0]=5
print(anotherL4)
#outputs correctly:
#[[[5, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
You're wrong. You've copied the reference multiple times, which means they're actually all the same list.
When you write list(L3 for i in range(4)), you are telling it to yield the same list L3 on each iteration of the generator comprehension. When you subsequently modify that list, the modifications show up everywhere, because all of them are references to the same list.
You could get the effect you seem to want by doing
list(list(L3) for i in range(4))
since using list(L3) makes a new list.
Just to elaborate,
a = 1
b = 2
c = [a,b]
a += 1
print c
Your problem is that you built a list of list references rather than a list of lists. Since the references all pointed back to a single list, when you mutate that single list, all the references show the change.
L0 = range(3)
L1 = range(3)
print(id(L0)) # prints a number
print(id(L1)) # prints a different number
print(id(L0) == id(L1)) # prints False
print(L0 is L1) # prints False; not same objects
print(L0 == L1) # prints True; values match
# your original code:
L2=list(0 for i in range(2))
L3=list(L2 for i in range(3))
L4=list(L3 for i in range(4))
print(L3[0] is L2) # prints True; L3[0] is a reference to L2
We can fix it and explicitly show what we are doing by using copy.deepcopy():
import copy
L2 = [0 for i in range(2)]
L3 = [copy.deepcopy(L2) for i in range(3)]
L4 = [copy.deepcopy(L3) for i in range(4)]
#give a new value to the very first number in list:
L4[0][0][0]=5
print("L4:")
print(L4)
Note that instead of making a generator expression and passing it to list() to force it to be expanded out to a list, I just used list comprehensions in the above code to directly make lists.
More usually if you want to do this crazy thing, you should maybe just nest some list comprehensions:
L4 = [[[0 for _ in range(2)] for _ in range(3)] for _ in range(4)]
This makes it pretty clear that we are building a new list of lists of lists. And if you use copy.deepcopy() you are basically just copying a bunch of zeroes, so you might as well just build new lists using zeroes.

Categories