Nested lists in python creating an issue - python-3.x

Let me first describe the question on which I am working.
Its a question from hackerrank - List Comprehensions.
Well here's my solution to that question :
final_list = [];
temp_list = [];
x = int(input());
y = int(input());
z = int(input());
n = int(input());
for i in range(x+1):
for j in range(y+1):
for k in range(z+1):
if((i + j + k) != n):
temp_list.clear();
temp_list.append(i);
temp_list.append(j);
temp_list.append(k);
final_list.append(temp_list);
print(final_list);
I used these values as my input : x = 1, y = 1 , z = 1 and n = 2.
Using these values I got output : [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]
I am not getting that even I cleared the temp_list then why am I getting this output instead of : [[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]].
and moreover, when I declared the temp_list in the if condition itself instead of declaring on the top of the code, I got the answer.
can anyone let me know why is this happening ?

Related

Get the distance from every element in a list to any other element

I have a list:
l = [10,22,3]
I'm trying to create a function that returns the distances (how close they are in the list itself), such that elements on the left of any element has a negative value, and those on its right has a positive value:
#optimal output
dis = [[0,1,2],[-1,0,1],[-2,-1,0]]
Is there a quick way to do that?
You could try a nested for-in loop. The idea here is to just retrieve the indexes of each value and its distance from other values.
nums = [10, 22, 3]
distances = []
for i in range(len(nums)):
for n in range(len(nums)):
distances.append(i-n)
print(distances)
Output:
[0, -1, -2, 1, 0, -1, 2, 1, 0]
Also, never name a variable l, because it looks like a 1.
Based on Leonardo's answer, to do what the OP commented:
nums = [10, 22, 3]
distances = []
for i in range(len(nums)):
temp = []
for n in range(len(nums)):
temp.append(n-i)
distances.append(temp)
print(distances)
Output:
[[0, 1, 2], [-1, 0, 1], [-2, -1, 0]]

Flipping bits in nested lists

I have a project wherein I have to use bit-flip mutation of genetic algorithm.
The code I have so far looks like this:
def mutation(pop, mr):
for i in range(len(pop)):
if (random.random() < mr):
if (pop[i] == 1):
pop[i] = 0
else:
pop[i] = 1
else:
pop[i] = pop[i]
return pop
mut = mutation(populations, 0.3)
print(mut)
For example, I have the following (depending on my project, populations can look like populations_1 or populations_2):
populations_1 = [[1, 0], [1, 1], [0, 1], [1, 0]]
populations_2 = [[1], [1], [0], [1]]
What I am doing is assigning random generated numbers to elements in populations and check if it is less than mutation rate. If it is, then bit-flip mutation will happen, if not, it will remain as it is. For the case of populations_1, if populations_1 index 2 is less than mutation rate, then it should become [1, 0]. For populations_2 index 3, it should become [0] if it is less than mutation rate. This is the objective of the mutation function.
Can anyone help me with turning the code I have so far to adapt situations like in populations_1? I think the code I have so far only works for populations_2.
Any help/suggestion/readings would be very much appreciated! Thanks!
You can use list comprehensions to do what you want. The values in pop are updated only if r<mr. To update them, you can iterate over each element (a) in list pop[i], and if a == 0 it becomes 1, otherwise 0. See the code below:
def mutation(pop, mr):
for i in range(len(pop)):
r = random.random()
print(r) # you can remove this line, it is only for testing
if r < mr:
pop[i] = [1 if a == 0 else 0 for a in pop[i]]
return pop
Test 1:
populations_1 = [[1, 0], [1, 1], [0, 1], [1, 0], [0,0]]
mut = mutation(populations_1, 0.3)
print(mut)
#random number for each iteration
0.3952226177233832
0.11290933711515283
0.08131952363738537
0.8489702326753509
0.9598842135077205
#output:
[[1, 0], [0, 0], [1, 0], [1, 0], [0, 0]]
Test 2:
populations_2 = [[1], [1], [0], [1]]
mut = mutation(populations_2, 0.3)
print(mut)
0.3846024893833684
0.7680389523799874
0.19371896835988422
0.008814288533701364
[[1], [1], [1], [0]]

What is the pythonic solution to enumerate and update items from a matrix?

I did a for loop using enumerate from values in a matrix and tried assigning a value to the items that are different than 0 while appending to a list elements that are equal to 0. The fact is that original matrix don't get updated.
Sample code:
matrix = [[0, 0, 0], [0, 1, 0], [1, 1, 1]]
current = []
for x, i in enumerate(matrix):
for y, j in enumerate(i):
if j == 0:
current.append((x, y))
else:
#matrix[x][y] = -1 # This works
j = -1 # This doesn't
Since this doesn't work, there is no utility in using enumerate for that case. So I changed the code to:
matrix = [[0, 0, 0], [0, 1, 0], [1, 1, 1]]
current = []
for x in range(len(matrix)):
for y in range(len(matrix[0])):
if matrix[x][y] == 0:
current.append((x, y))
else:
matrix[x][y] = -1
The code above IMO is much less readble and also pylint suggests against using that with:
C0200: Consider using enumerate instead of iterating with range and
len (consider-using-enumerate)
You can't just update 2d array in-place through assigning to local variable j = -1 (which is reinitialized on each loop iteration for y, j in enumerate(i)).
In your simple case you can update your matrix with the following simple traversal:
matrix = [[0, 0, 0], [0, 1, 0], [1, 1, 1]]
for i, row in enumerate(matrix):
for j, val in enumerate(row):
if val != 0: matrix[i][j] = -1
print(matrix) # [[0, 0, 0], [0, -1, 0], [-1, -1, -1]]
Though Numpy provides a more powerful way for updating matrices:
import numpy as np
matrix = np.array([[0, 0, 0], [0, 1, 0], [1, 1, 1]])
matrix = np.where(matrix == 0, matrix, -1)
print(matrix)

Efficiently Loop Through Millions of Elements

I have a list of 262144 elements in a list created through "itertools.product". Now I have to loop over these elements and multiply it with all other elements, which is taking too much time. (I don't have any issue of memory / cpu)
elements = []
for e in itertools.product(range(4), repeat=9):
elements.append(e)
for row in elements:
for col in elements:
do_calculations(row, col)
def do_calculations(ro, co):
t = {}
t[0] = [multiply(c=ro[0], r=co[0])]
for i in range(1, len(ro)):
_t = []
for j in range(i+1):
_t.append(multiply(c=ro[j], r=co[i-j]))
t[i] = _t
for vals in t.values():
nx = len(vals)
_co = ro[nx:]
_ro = co[nx:]
for k in range(len(_ro)):
vals.append(multiply(c=_co[k], r=_ro[k]))
_t = []
for k in t.values():
s = k[0]
for j in range(1, len(k)):
s = addition(c=s, r=k[j])
_t.append(s)
return _t
def addition(c, r) -> int:
__a = [[0, 3, 1, 2],
[3, 2, 0, 1],
[0, 3, 2, 1],
[1, 0, 2, 3]]
return __a[c][r]
def multiply(c, r) -> int:
__m = [[0, 0, 0, 0],
[0, 1, 2, 3],
[0, 3, 1, 2],
[0, 2, 3, 1]]
return __m[c][r]
it is taking too much time to process single col with rows....
can any one help me in this?
regards
Not much of a python guy but
make sure col is a higher number than row (small optimization, but optimization nevertheless)
use a multiprocessing library (alink). that should cut the calculation time.
(as noted in comment by #Skam, multithreading does not increase performance in such case)
also, you might consider some optimizations in the calculation itself.

Adding sublist to list in python3 not working

I have a really weird issue in Python3. I have some code that generates some different list from a list of integers (what this does exactly is not relevant).
def get_next_state(state):
max_val = max(state)
max_index = state.index(max_val)
new_state = state
for n in range(max_val + 1):
new_state[max_index] -= 1
new_state[(n + max_index) % len(state)] += 1
return new_state
Now all I want to do is add a next state to some list that keeps the states. This is my code:
l = [0, 2, 7, 0]
seen_states = []
for _ in range(10):
print(l)
seen_states += [l]
l = get_next_state(l)
print(seen_states)
For some reason list l is assigned correctly when I print it, but it is not added correctly to the list of seen states. Note that I have also tried seen_states.append(l) instead of using += [l]. Does anyone know why this happend?
To prevent these problems use copy, deepcopy or list[:]
import copy
def get_next_state(state):
max_val = max(state)
max_index = state.index(max_val)
new_state = copy.deepcopy(state)
for n in range(max_val + 1):
new_state[max_index] -= 1
new_state[(n + max_index) % len(state)] += 1
return new_state
You are sending your list l inside the function. When you assign it to another name, you are not making a copy but referencing the original object. Any modification on these lists is a change in the original object.
Using new_state = state[:] (copies the list instead of referencing the original) in the get_next_state produces the following output:
[0, 2, 7, 0]
[2, 4, 1, 2]
[3, 1, 2, 3]
[0, 2, 3, 4]
[1, 3, 4, 1]
[2, 4, 1, 2]
[3, 1, 2, 3]
[0, 2, 3, 4]
[1, 3, 4, 1]
[2, 4, 1, 2]
[[0, 2, 7, 0], [2, 4, 1, 2], [3, 1, 2, 3], [0, 2, 3, 4], [1, 3, 4, 1], [2, 4, 1, 2], [3, 1, 2, 3], [0, 2, 3, 4], [1, 3, 4, 1], [2, 4, 1, 2]]
Not sure if this is your desired output, as you did not specify what you are getting as "wrong" output

Resources