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

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]

Related

Find all possible replacements for 1s and 0s in a list

Input:
table = [
[1, ''],
['', 0]
]
Desired output:
[[[1, 0], [0, 0]], [[1, 0], [1, 0]], [[1, 1], [0, 0]], [[1, 1], [1, 0]]]
Tried to do it with recursion like this:
def get_tables(tab, out_tab):
changes = 0
for row_i, row in enumerate(tab):
for val_i, val in enumerate(row):
if val == '':
changes = 1
tab[row_i][val_i] = 0
get_tables(tab, out_tab)
tab[row_i][val_i] = 1
get_tables(tab, out_tab)
if changes == 0:
out_tab.append(tab)
But it returns only 1s
Edit:
So the logic is: find '' in list and then create two lists, one with 1 instead of '' and one with 0 (like [1, ''] to [1, 0] and [1, 1]). Do the same operation with those two lists, and continue until there's no ''. Return all this lists in one.
Not the most efficient solution, but it works:
table = [
[1, ''],
['', 0]
]
import copy
# locations where element is ''
locs = [[idx_r, idx_c] for idx_r, row in enumerate(table) for idx_c, element in enumerate(row) if element == '']
len_locs = len(locs)
tables = []
for i in range(2 ** len_locs): # for n locations, we have 2**n permutations of 1 and 0
table_copy = copy.deepcopy(table)
permutation = list(map(int, f'{i:0{len_locs}b}')) # convert i to the binary to get current permutation
for it, (idx_r, idx_c) in enumerate(locs):
table_copy[idx_r][idx_c] = permutation[it]
tables.append(table_copy)
print(tables)
>>> [[[1, 0], [0, 0]], [[1, 0], [1, 0]], [[1, 1], [0, 0]], [[1, 1], [1, 0]]]

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 my code looping and displaying random lists from my for loop?

I have a project that goes like this:
Variables:
avail_res = [6, 4]
q_active = [2, 3, 4]
score = [3, 0, 10, 5]
populations = [[1, 0, 0], [0, 0, 0], [0, 1, 1], [0, 0, 1]]
chromosomes = []
for num in score:
if num <= avail_res[0]:
chromosomes.append(populations[score.index(num)])
if len(chromosomes) > 1:
k = random.choice(chromosomes)
chromosome_best = k
else:
chromosome_best = chromosomes
act = numpy.array([q_active[i] for i in numpy.flatnonzero(chromosome_best)])
The objective is to get activity in q_active corresponding to the non-zero value in chromosome_best. With the code above, the 1st step is to compare each element in score to avail_res[0]. If it satisfies the condition, then its corresponding population will be obtained and stored in chromosome_best where the non-zero value is used to get corresponding element in q_active. If chromosome_best is more than 1, then, it should choose which to select randomly.
The problem is after getting the output, the for loop is still 'looping'. So I am getting an output like this:
Output = [[1, 0, 0]] # obtained from the first loop
[0, 0, 0] # randomly selected on the 2nd iteration of for loop
[0, 0, 0] # randomly selected on the 3rd iteration of for loop
Expected Output for Populations = [[1, 0, 0]]
Expected Output for act = [2]
How could I make my code free from looping but still consider it when checking for the condition ( <= avail_res[0] )?
I tried making it if [num <= avail_res[0] for num in score]: but num gets undefined.
Any help would be appreciated! Thanks!
I would expect your code to be structured more like:
numpy
import random
avail_res = [4, 6]
q_active = [2, 3, 4]
scores = [3, 2, 8, 10]
populations = [[1, 0, 1], [0, 0, 1], [1, 1, 0], [1, 1, 1, 0]]
chromosomes = []
for score in scores:
if score <= avail_res[0]:
chromosomes.append(populations[scores.index(score)])
chromosome_best = random.choice(chromosomes)
act = numpy.array([q_active[i] for i in numpy.flatnonzero(chromosome_best)])
print(chromosome_best)
print(act)
An open question in my mind is why you only look at avail_res[0] and not the rest of avail_res -- i.e. we need to understand more about what's going on. Also, no need to handle a single entry in chromosomes specially, the random.choice() function will cope just fine.

How can I change the view of my list?

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)]

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.

Categories