Related
I would like to know how it is possible to obtain the diagonals that point downwards (left and right) with respect to a specific index of the matrix.
To be more graphic I will give the following example of an expected output:
matrix = np.array([[2, 0, 0, 2],
[3, 9, 8, 3],
[3, 0, 0, 2],
[0, 0, 0, 0]])
Expected output results for position: matrix[1][2]
matrix[1][2]
8
diag_right = [2]
diag_left = [0, 0]
Same example but using the matrix in matrix[1][2]
matrix = np.array([[x, x, x, x],
[x, x, 8, x],
[x, 0, x, 2],
[0, x, x, x]])
An easy way using numpy would be:
(i've changed the matrix to make more clear some results in test_ij)
import numpy as np
def get_right_left_diags(matrix,i,j):
n = len(matrix)
left_diag = np.diag(matrix[i+1:n,j+1:n])
right_diag = np.diag( matrix[i+1:n, j-1::-1])
return right_diag,left_diag
%lets check some results
matrix = np.array([[2, 0, 0, 2],
[3, 9, 8, 3],
[3, 0, 0, 2],
[1, 2, 3, 4]])
n = len(matrix)
cases = [[0,0],[0,3],[1,1],[1,2],[2,1]]
for i,j in cases:
right_diag,left_diag = get_right_left_diags(matrix,i,j)
print(f"i={i}, j={j}, left_diag: {left_diag} \t right_diag: {right_diag}")
this will output:
#i=0, j=0, left_diag: [9 0 4] right_diag: [3 0 2]
#i=0, j=3, left_diag: [] right_diag: [8 0 1]
#i=1, j=1, left_diag: [0 4] right_diag: [3]
#i=1, j=2, left_diag: [2] right_diag: [0 1]
#i=2, j=1, left_diag: [3] right_diag: [1]
for me it has total sense.
matrix = np.array([[2, 0, 0, 2],
[3, 9, 8, 3],
[3, 0, 0, 2],
[0, 0, 0, 0]])
i = 1; j = 2
diag_right = []; diag_left = []
for k in range(1, len(matrix) - i):
if(j+k < len(matrix[0])):
diag_right.append(matrix[i+k][j+k])
if(j-k >= 0):
diag_left.append(matrix[i+k][j-k])
Is this what you're looking for?
Given a matrix, A of size M x N of 0s and 1s. If an element is 0, set its entire row and column to 0.
Input 1:
[ [1, 0, 1],
[1, 1, 1],
[1, 1, 1] ]
Output 1:
[ [0, 0, 0],
[1, 0, 1],
[1, 0, 1] ]
My Code:
def setZeroes(self, A):
B=A
for i in range(len(A)):
for j in range(len(A[i])):
if(A[i][j]==0):
for x in range(len(A[i])):
B[i][x]=0
for y in range(len(A)):
B[y][j]=0
A=B
return A
Is creating a zero matrix. What do I miss ?
You can do it by masking rows and columns with a zero
mask = A==0
A[:, mask.any(0)] = 0
A[mask.any(1)] = 0
print(A)
array([[0, 0, 0],
[1, 0, 1],
[1, 0, 1]])
import copy
def setZeroes(A):
B=copy.deepcopy(A)
for i in range(len(A)):
for j in range(len(A[i])):
if(A[i][j]==0):
for x in range(len(A[i])):
B[i][x]=0
for y in range(len(A)):
B[y][j]=0
return B
A = [ [1, 0, 1],
[1, 1, 1],
[1, 1, 1] ]
print(setZeroes(A))
since, array is pass by reference, you have to deepcopy it.
def func(l):
r = []
c = []
# storing the index value of coloum and row where there is 0 everywhere
for i,v1 in enumerate(l):
for j,v2 in enumerate(v1):
if v2 ==0:
c.append(j)
r.append(i)
r = list(set(r))
c = list(set(c))
# making all element of row 0
for i in r:
for j in range(len(l[i])):
l[i][j] = 0
# making lal element of coloumn 0
for i in c:
for j in range(len(l)):
l[j][i] = 0
return l
l = [ [1, 0, 1],
[1, 1, 1],
[1, 1, 1] ]
res = func(l)
print(res,sep='\n')
output:
[
[0, 0, 0],
[1, 0, 1],
[1, 0, 1]
]
Your problem is right here:
B=A
This doesn't create three new arrays for the rows of B: it makes B point to the same arrays as A. So as soon as you set the first row and column to zeros, there are additional zeroes which your loop discovers. Copy each row (or deep copy) to avoid the problem.
This is a simple answer which does not modify A but create another matrix which is returned:
from more_itertools import locate
def setZeroes(A):
indexPosList = [] # will contains all the zeroable indices
result = [] # the result matrix
for i in A:
indexPosList.extend(list(locate(i, lambda a: a == 0)))
if 0 in i:
result.append([0]*len(i))
else:
for idx in indexPosList:
i[idx] = 0
result.append(i)
return result
Sample test:
>>> A = [[1, 0, 1], [1, 1, 1], [1, 1, 1]]
>>> setZeroes(A)
[[0, 0, 0], [1, 0, 1], [1, 0, 1]]
This is a full python implementation that correctly changes A in place including changing columns
def set_zero(A):
columns = set()
for row_nr, row in enumerate(A):
if 0 in row:
columns |= {i for i, c in enumerate(row) if c == 0}
A[row_nr] = [0] * len(row)
for row_nr, row in enumerate(A):
A[row_nr] = [0 if i in columns else c for i, c in enumerate(row)]
I am creating a program that needs to change all of a certain column's values to 1. Originally I thought that n[:][0] = 1 would have been sufficient, but it doesn't work.
n = [[0] * 3 for _ in range(3)]
print(n) #output: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[...] #change all of column 0 of 2d list "n" to 1
print(n) #output: [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
Here's an overboard one liner:
result = list(map(lambda x: list(map(lambda y: y[1] + 1 if y[0] == 0 else y[1], enumerate(x))), n))
print(result)
# [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
Or something even easier to read, as suggested in the comments:
[[1 if c == 0 else j for c,j in enumerate(k)] for k in n]
In comparison to a simple loop where you update the element in place:
for x in n:
x[0] = 1
print(n)
# [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
Note: The first way using lambda(map(...)) is just a joke, by no means use it. It's main purpose was to just show the contrast between trying to get a one liner, and just using a simple loop to do the job.
EDIT:
#Stefan Pochmann in the comments recommended this one-liner solution:
[[1] + k[1:] for k in n]
Which creates a new structure, instead of modifying the elements in place.
big hammer approach - if you want array addressing, import numpy
import numpy as np
n = [[0] * 3 for _ in range(3)]
nary = np.array(n) # or: np.zeros((3,3))
nary[:, 0] = 1
nary.tolist()
Out[120]: [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
I am a noob in python
Well i watched a video from numberphile (https://youtu.be/1MtEUErz7Gg)
that was about sandpiles (adding them) so i decided to write my own python program to add 2 sandpiles.
but for some reason it does not work
The program gives me the wrong sum like 2+2=7 type wrong
it should give me:
[ [2, 2, 0], [2, 1, 1], [0, 1, 3] ] + [ [2, 1, 0], [1, 0, 1], [3, 1, 0] ] =
[[2, 1, 0],[0, 3, 3],[1, 2, 3] ]
but instead gives:
[ [2, 2, 0], [2, 1, 1], [0, 1, 3] ] + [ [2, 1, 0], [1, 0, 1], [3, 1, 0] ] =
[[1, 3, 3], [0, 1, 2], [2, 2, 3]]
This is my code
X = [ [2, 2, 0], [2, 1, 1], [0, 1, 3] ]
Y = [ [2, 1, 0], [1, 0, 1], [3, 1, 0] ]
xy = [ [0, 0, 0], [0, 0, 0], [0, 0, 0] ]
i = j = 0
while (i < 3):
while(j < 3):
xy[i][j] = X[i][j] + Y[i][j]
j = j + 1
i = i + 1
j = 0
def get_above(pile):
found = False
while not found:
i, j = 0,0
while (i < 3):
while (j < 3):
if(pile[i][j] > 3):
return i, j
j = j + 1
i = i + 1
j = 0
found = True
return True
def tupple_pile():
while get_above(xy):
i, j = get_above(xy)
neg = [ [i, j+1], [i+1, j], [i, j-1], [i-1,j] ]
neg = [n for n in neg if n[0] in [0, 1, 2] and n [1] in [0, 1, 2]]
k = 0
while k < len(neg):
p = neg[k][0]
q = neg[k][1]
xy[p][q] = xy[p][q] + 1
k = k + 1
xy[i][j] = xy[i][j] - 4
return xy
tupple_pile()
You really should be more specific in your question. Running your code as it is results in Errors.
Anyhow, one thing that looks strange is the check function. Is it supposed to filter out indices that are outside the sandpile? In that case I think you will see something missing here:
if (neg[i][j] < 0) or (neg[i][j]):
Try with this instead:
if (neg[i][j] < 0) or (neg[i][j] > 2):
The second problem with this loop is that you are deleting elements from neg del(neg[i]) while iterating over it. This is error prone. And as you may have noticed, as soon as you delete an item, the i will go out of range.
A better way to filter a list is to use a list comprehension, something like this:
neighbors = [ [i, j+1], [i+1, j], [i, j-1], [i-1,j] ]
neighbors = [n for n in neighbours if n[0] in [0, 1, 2] and n[1] in [0, 1, 2]]
My matrix is a 8x8 having binary values. I want to filter out patterns of consecutive three 1's i.e.(111) in the diagonals of upper triangular matrix of M. I have written a piece of python code with for and while loop but it did not work and I am unable to figure out whats happening there. Please help..
rf =([1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0])
for i in range(1):
for j in range(len (rf)-3):
while (i<len(rf)-3 and j<len(rf)-3):
count =0
if rf[i,j]==True:
for w in range(3):
if rf[i+w,j+w]==True:
count +=1
print count
if count==3:
i=i+3
j=j+3
else:
rf[i,j]=False
i=i+1
j=j+1
You might simplify your code using numpy to access diagonals:
>>> import numpy as np
>>> rf = [[1,0,1,0,1,0,0,0]] * 8
>>> m = np.array(rf)
>>> m.diagonal(0)
array([1, 0, 1, 0, 1, 0, 0, 0])
>>> m.diagonal(1)
array([0, 1, 0, 1, 0, 0, 0])
a simply routine to find positions of consecutive ones:
def consecutive_values(arr, val=1, cnt=3):
def comparator(pos):
return arr[pos] == val
if len < cnt:
return []
else:
return [p for p, x in enumerate(arr[:1-cnt])
if all(map(comparator, xrange(p, p+cnt, 1)))]
and usage:
>>> consecutive_values([1]*5)
[0, 1, 2]
>>> consecutive_values([1]*5 + [0]*4 + [1]*3)
[0, 1, 2, 9]
>>> m = np.array([[1]*8]*8)
>>> diagonals = map(m.diagonal, range(len(m)))
>>> map(consecutive_values, diagonals)
[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4], [0, 1, 2, 3], [0, 1, 2], [0, 1], [0], [], []]