Python - two-dimensional array adressing fills up the whole array - python

I have a problem. First let me show you the code:
def neon(l):
oc = 0; #naj ocena
tz = 0; #teraz ocena
#sprawdzanie poziomo
for x in range(len(l[0])):
for i in range(len(l[x])):
for y in range(i + 1,len(l[x])):
tz = l[x][i] + l[x][y] + (max(y - x, x - y) + 1) * 2;
if (tz > oc):
oc = tz;
pion = [[0] * len(l[0])] * len(l);
print(pion);
print("#######");
for i in range(len(pion)):
for y in range(len(pion[i])):
pion[i][y] = l[y][i];
print(pion);
neon([[1,2,1,2],[7,1,7,1],[1,1,1,1],[3,3,3,3]]);
The problem is that when i try to adress pion[i][y] instead of just changing that value from 0 to whatever the program changes the value in all of the inner arrays with the second index y. This is how it looks:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
#######
[[1, 7, 1, 3], [1, 7, 1, 3], [1, 7, 1, 3], [1, 7, 1, 3]]
[[2, 1, 1, 3], [2, 1, 1, 3], [2, 1, 1, 3], [2, 1, 1, 3]]
[[1, 7, 1, 3], [1, 7, 1, 3], [1, 7, 1, 3], [1, 7, 1, 3]]
[[2, 1, 1, 3], [2, 1, 1, 3], [2, 1, 1, 3], [2, 1, 1, 3]]
Instead, it should be:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
#######
[[1, 7, 1, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[1, 7, 1, 3], [2, 1, 1, 3], [0, 0, 0, 0], [0, 0, 0, 0]]
[[1, 7, 1, 3], [2, 1, 1, 3], [1, 7, 1, 3], [0, 0, 0, 0]]
[[1, 7, 1, 3], [2, 1, 1, 3], [1, 7, 1, 3], [2, 1, 1, 3]]
Please help and thank you in advance.

This problem occurs due to the following reasons:
pionis a list of inner lists. Each element of pion just holds the reference to one inner list.
Because of the way you have created and initialized pion (using pion = [[0] * len(l[0])] * len(l)), all elements of pion hold references to the same inner list. So, in pion, instead of many distinct inner lists, you just have multiple references to a single inner list. In other words, pion[0], pion[1], pion[2], etc, are all references to the same inner list of zeros. Any modification that you make to this inner list, using a particular row index (eg, using the expression pion[3]), will be visible through all the other row indexes also, because, at all row indexes, you are just holding a reference to the same inner list.
To correct this, you need to create and initialize the list differently. Eg, if rows and cols are respectively the number of rows and columns, you could do something like this:
pion = [([0]*cols) for i in range(rows)]

Related

Find most common value in numpy 2d array rows, otherwise return maximum

I have an array like this
Nbank = np.array([[2, 3, 1],
[1, 2, 2],
[3, 2, 1],
[3, 2, 1],
[2, 3, 2],
[2, 2, 3],
[1, 1, 3],
[2, 1, 1],
[2, 2, 3],
[1, 1, 1],
[2, 1, 1],
[2, 3, 1],
[1, 2, 1]])
I want to return an array with only one column. The condition is to return the most common value in each row; if multiple values have the same number of occurrences, just return the maximum of them.
I used this code
most_f = np.array([np.bincount(row).argmax() for row in Nbank])
if multiple values have the same number of occurrences, it returns the first item instead of the maximum. how can I work this around?
You could use a Counter after sorting in descending order by row. There's a most_common that will return what you want. Since it's sorted already, the first element is always either the largest or the most frequent.
import numpy as np
from collections import Counter
Nbank = np.array([[2, 3, 1],
[1, 2, 2],
[3, 2, 1],
[3, 2, 1],
[2, 3, 2],
[2, 2, 3],
[1, 1, 3],
[2, 1, 1],
[2, 2, 3],
[1, 1, 1],
[2, 1, 1],
[2, 3, 1],
[1, 2, 1]])
np.array([Counter(sorted(row, reverse=True)).most_common(1)[0][0] for row in Nbank])
Output
array([3, 2, 3, 3, 2, 2, 1, 1, 2, 1, 1, 3, 1])
I believe this will solve the problem. You could probable make it into a one liner with some fancy list comprehension, but I don't think that would be worth while.
most_f = []
for n in Nbank: #iterate over elements
counts = np.bincount(n) #count the number of elements of each value
most_f.append(np.argwhere(counts == np.max(counts))[-1][0]) #append the last and highest
You can cheat a little bit and reverse each row in order to make np.argmax return indice of the rightmost occurence which corresponds to the largest item:
N = np.max(arr)
>>> [N - np.argmax(np.bincount(row, minlength=N+1)[::-1]) for row in Nbank]
[3, 2, 3, 3, 2, 2, 1, 1, 2, 1, 1, 3, 1]
You might also like to avoid loops which is definitely adviseable if you want to take full advantages of numpy. Unfortunately np.bincount is not supported for 2D arrays but you can do it manually:
N, M = arr.shape[0], np.max(arr)+1
bincount_2D = np.zeros(shape=(N, M), dtype=int)
advanced_indexing = np.repeat(np.arange(N), arr.shape[1]), arr.ravel()
np.add.at(bincount_2D, advanced_indexing, 1)
>>> bincount_2D
array([[0, 1, 1, 1],
[0, 1, 2, 0],
[0, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 2, 1],
[0, 0, 2, 1],
[0, 2, 0, 1],
[0, 2, 1, 0],
[0, 0, 2, 1],
[0, 3, 0, 0],
[0, 2, 1, 0],
[0, 1, 1, 1],
[0, 2, 1, 0]])
And then repeat the process for all the rows simultaneously:
>>> M -1 - np.argmax(bincount_2D[:,::-1], axis=1)
array([3, 2, 3, 3, 2, 2, 1, 1, 2, 1, 1, 3, 1], dtype=int64)

get lines where value does not exist

I'm trying to get from 2D list the lines where value = 2 does not exists:
[[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
I've been using:
for i in range(len(list)):
if list[i] in [list]:
# dot stuff
the problem here is that evrytime the code is using the actual line which is list[i] and ignore the the rest even if 2 does not exists on it
hope Iwas clear
Thank you
something like the below
lst = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
lst = [x for x in lst if 2 not in x]
print(lst)
output
[[0, 0, 1, 1], [0, 0, 1, 0]]
Is this your expected output?
[0, 0, 1, 1]
[0, 0, 1, 0]
This is the working code:
a = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
for i in range(len(a)):
if 2 not in a[i]:
print(a[i])

Generate Numpy array of even integers that sum to a value

Is there a numpy solution that would allow you to initialize an array based on the following conditions?
Number of elements in axis 1. (In the example below you have 4 places in each element of the array)
Sum of values. (All elements sum to 8)
Step size. (Using increments of 2)
Essentially this shows all the combinations of 4 values you can add to achieve the wanted sum (8) at a step size of 2.
My experiments fail when I set the axis 1 dimension to over 6 and the sum to over 100.
There has to be a better way to do this than what I've been trying.
array([[0, 0, 0, 8],
[0, 0, 2, 6],
[0, 0, 4, 4],
[0, 0, 6, 2],
[0, 0, 8, 0],
[0, 2, 0, 6],
[0, 2, 2, 4],
[0, 2, 4, 2],
[0, 2, 6, 0],
[0, 4, 0, 4],
[0, 4, 2, 2],
[0, 4, 4, 0],
[0, 6, 0, 2],
[0, 6, 2, 0],
[0, 8, 0, 0],
[2, 0, 0, 6],
[2, 0, 2, 4],
[2, 0, 4, 2],
[2, 0, 6, 0],
[2, 2, 0, 4],
[2, 2, 2, 2],
[2, 2, 4, 0],
[2, 4, 0, 2],
[2, 4, 2, 0],
[2, 6, 0, 0],
[4, 0, 0, 4],
[4, 0, 2, 2],
[4, 0, 4, 0],
[4, 2, 0, 2],
[4, 2, 2, 0],
[4, 4, 0, 0],
[6, 0, 0, 2],
[6, 0, 2, 0],
[6, 2, 0, 0],
[8, 0, 0, 0]], dtype=int64)
Here is a small code that will enable you to loop over the desired combinations. It takes 3 parameter:
itsize: Number of elements.
itsum: Sum of values.
itstep: Step size.
It may be necessary to optimize it if the computations you do in the FOR loop are light. I loop over more combinations than necessary (all the i,j,k,l that take values in 0,itstep,2*itstep,...,itsum) and keep only those verifying the condition that all sum up to itsum. The big size array is not computed and the rows are computed on-the-fly when iterating so you will not have the memory troubles:
class Combinations:
def __init__(self, itsize, itsum, itstep):
assert(itsum % itstep==0) # Sum is a multiple of step
assert(itsum >= itstep) # Sum bigger or equal than step
assert(itsize > 0) # Number of elements >0
self.itsize = itsize # Number of elements
self.itsum = itsum # Sum parameter
self.itstep = itstep # Step parameter
self.cvalue = None # Value of the iterator
def __iter__(self):
self.itvalue = None
return self
def __next__(self):
if self.itvalue is None: # Initialization of the iterator
self.itvalue = [0]*(self.itsize)
elif self.itvalue[0] == self.itsum: # We reached all combinations the iterator is restarted
self.itvalue = None
return None
while True: # Find the next iterator value
for i in range(self.itsize-1,-1,-1):
if self.itvalue[i]<self.itsum:
self.itvalue[i] += self.itstep
break
else:
self.itvalue[i] = 0
if sum(self.itvalue) == self.itsum:
break
return self.itvalue # Return iterator value
myiter = iter(Combinations(4,8,2))
for val in myiter:
if val is None:
break
print(val)
Output:
% python3 script.py
[0, 0, 0, 8]
[0, 0, 2, 6]
[0, 0, 4, 4]
[0, 0, 6, 2]
[0, 0, 8, 0]
[0, 2, 0, 6]
[0, 2, 2, 4]
[0, 2, 4, 2]
[0, 2, 6, 0]
[0, 4, 0, 4]
[0, 4, 2, 2]
[0, 4, 4, 0]
[0, 6, 0, 2]
[0, 6, 2, 0]
[0, 8, 0, 0]
[2, 0, 0, 6]
[2, 0, 2, 4]
[2, 0, 4, 2]
[2, 0, 6, 0]
[2, 2, 0, 4]
[2, 2, 2, 2]
[2, 2, 4, 0]
[2, 4, 0, 2]
[2, 4, 2, 0]
[2, 6, 0, 0]
[4, 0, 0, 4]
[4, 0, 2, 2]
[4, 0, 4, 0]
[4, 2, 0, 2]
[4, 2, 2, 0]
[4, 4, 0, 0]
[6, 0, 0, 2]
[6, 0, 2, 0]
[6, 2, 0, 0]
[8, 0, 0, 0]
I tried this out and also found that it slowed down significantly at that size. I think part of the problem is that the output array gets pretty large at that point. I'm not 100% sure my code is right, but the plot shows how the array size grows with condition 2 (sum of values in each row). I didn't do 100, but it looks like it would be about 4,000,000 rows
plot

Transferring Values in nested dictionaries/lists

list = [[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2],
[2, 3, 1, 0, 0], [3, 0, 1, 2, 0], [2, 0, 1, 3, 0]]
I would like to check if the number 1 is in the third column of all the nested lists, if it is than it should replace the 1 with a 0 and the 2 in that list with a 1.
Thanks in advance
Try the following:
nested_lists = [[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2],
[2, 3, 1, 0, 0], [3, 0, 1, 2, 0], [2, 0, 1, 3, 0]]
for list_ in nested_lists:
if list_[2] == 1:
list_[2] = 0
list_ = [1 if n == 2 else n for n in list_]
After execution, nested_lists goes from the given
[[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2],
[2, 3, 1, 0, 0], [3, 0, 1, 2, 0], [2, 0, 1, 3, 0]]
To
[[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2]
[1, 3, 0, 0, 0], [3, 0, 0, 1, 0], [1, 0, 0, 3, 0]]

Permutations in python without libraries

I am trying to produce a function that should takes as input a range, and for that range should be return all the possible permutation of that range without use any library.
for example:
per(range(3))
should return:
[[0, 1, 2], [1, 0, 2], [1, 2, 0], [0, 2, 1], [2, 0, 1], [2, 1, 0]]
I have done the following but i get an empty list.
def per(l):
return [l[i]+p for i in range(len(l))for p in per(l[:i] + l [i+1:])]
Does anyone know why i get the empty list and how to solve it?
The issue is that the end condition for you would be when the length of list l is 0 and that returns an empty list back. Hence when length of list is 1, the inner loop never actually runs and hence this also returns an empty list back , and this keeps on happenning and you always get empty lists.
An fix would be to make the end condition when the length of list is 1, and you should return lists of lists, not simple lists. Example -
def per(l):
if len(l) == 1:
return [l]
return [[l[i]] + p for i in range(len(l))for p in per(l[:i] + l [i+1:])]
Demo -
>>> def per(l):
... if len(l) == 1:
... return [l]
... return [[l[i]] + p for i in range(len(l))for p in per(l[:i] + l [i+1:])]
...
>>>
>>> per([2])
[[2]]
>>> per([0,1,2])
[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
>>> per([0,1,2, 3])
[[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2], [0, 3, 2, 1], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3], [1, 2, 3, 0], [1, 3, 0, 2], [1, 3, 2, 0], [2, 0, 1, 3], [2, 0, 3, 1], [2, 1, 0, 3], [2, 1, 3, 0], [2, 3, 0, 1], [2, 3, 1, 0], [3, 0, 1, 2], [3, 0, 2, 1], [3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]]
>>> len(per([0,1,2, 3]))
24

Categories

Resources