Copies and bindings between python objects - python

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

Related

How to find all the permutations of a variable amount of 0's and 1's recursively (without using itertools or random)?

I'm trying to produce all permutations of a certain number of numbers (for example, 0s and 1s) for a variable number of positions. I will call the number of numbers ord (e.g. ord=2 for only 0s and 1s; ord=3 for 0s, 1s, and 2s) and the number of positions Num. Hence the number of permutations is ord**Num.
Note: I don't want to use itertools or any other types of built-in functions. I'm asking this out of curiosity, not just trying to find a solution.
For ord=2 and Num=3, the output, in any order, should be:
[[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
This can be accomplished by:
ord = 2
mylist = []
for a in range(ord):
for b in range(ord):
for c in range(ord):
mylist.append([a,b,c])
For ord = 2 and Num = 4, the output should be:
[[0,0,0,0],[0,0,0,1],[0,0,1,0],[0,0,1,1],[0,1,0,0],[0,1,0,1],[0,1,1,0],[0,1,1,1],[1,0,0,0],[1,0,0,1],[1,0,1,0],[1,0,1,1],[1,1,0,0],[1,1,0,1],[1,1,1,0],[1,1,1,1]]
But then I would have to add another nested for loop:
ord = 2
mylist = []
for a in range(ord):
for b in range(ord):
for c in range(ord):
for d in range(ord):
mylist.append([a,b,c,d])
An obvious solution is to add 0s and 1s randomly to a list of length Num and then to accept that list if it hasn't already been added to mylist, but I want a solution that isn't quite so ridiculous.
This is the closest I've gotten so far to a real solution:
def myperms(elem, mylist):
for i in range(len(elem)-1,-1,-1):
while (elem[i] + 1) < ord:
elem = list(elem)
elem[i] += 1
if elem not in mylist:
mylist.append(elem)
if (elem[i] + 1) >= ord:
elem = list(elem)
elem[i] = 0
return mylist
Num = 3
ord = 2
TotsNum = ord**Num
mylist = []
elem = [0,]*Num
mylist.append(elem)
print(myperms(elem, mylist))
But this only gives:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0]]
I've tried calling the function within itself (recursion), but I haven't been able to figure out how to do it properly. Does anyone have any ideas about how to solve it recursively? Thank you!
Let's use a recursive solution:
def get_seq(ord, num):
val = [0]*num
N = num
def recurse(ord, num):
for i in range(ord):
val[N - num] = i
if num > 1:
yield from recurse(ord, num-1)
else:
yield val[:]
return recurse(ord, num)
print(list(get_seq(2, 4)))
Output:
[[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 1, 1, 0],
[0, 1, 1, 1],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 0, 1],
[1, 1, 1, 0],
[1, 1, 1, 1]]
For other inputs:
>>> list(get_seq(3, 2))
[[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
Use binary, which consists of 0s and 1s.
n = 4
all_permutations = []
for i in range(2**n):
permutation = []
string = bin(i)
string = string.split("0b")[1]
while len(string) != n:
string = f"0{string}"
for i in string:
permutation.append(int(i))
all_permutations.append(permutation)
print(all_permutations)

creating list of lists of premutations without changing certain values in the orginal list

im trying to write a nonogram program and having a trouble with understanding the following:
I'm trying to create a nested list using recursion from the following parameters:
row: a list made of 1, 0 or -1, eg. [0,-1,-1,1]
lst: an empty lst that will be built as an single option
i: the index the recursion will run with
*final: the final list of lists that will be built
1 and 0 in the original list have to remain unchanged and -1 has to be changed to 0 or a 1.
i have to return a list of list with representing all the options that can be assembled from the original list
here are some examples -
input: `[-1,1,1,-1,1]`
output: `[[1, 1, 1, 1, 1], [1, 1, 1, 0, 1], [0, 1, 1, 1, 1], [0, 1, 1, 0, 1]]`
input:`[-1,-1,-1]`
output:`[[1, 1, 1], [1, 1, 0], [1, 0, 1], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 0, 1], [0, 0, 0]]`
input:`[0,-1,-1]`
output: `[[0, 1, 1], [0, 1, 0], [0, 0, 1], [0, 0, 0]]`
this code does work for situations like [-1,-1,-1] but does not work for input like the first expample. it chnages 0 and 1 from the original list but it shouldnt
BLACK = 1
WHITE = 0
UNKNOWN = -1
def row_helper(row, lst, i, final):
if len(lst) == len(row):
copied = copy.deepcopy(lst)
final.append(copied)
return
if row[i] == BLACK or row[i] == WHITE:
lst.append(row[i])
row_helper(row, lst, i + 1, final)
else:
lst.append(BLACK)
row_helper(row, lst, i + 1, final)
lst.pop()
lst.append(WHITE)
row_helper(row, lst, i + 1, final)
lst.pop()
final1 = []
j = 0
lst2 = []
row1 = [1, 0, -1, -1]
row_helper(row1,lst2, j, final1)
i tried replacing the list editing with tuple and than converting to a list later and this code does work for every situation but im trying to figure out how to fix the first code without using tuples
this is the one that work:
def row_helper(row, temp_tup, i, valid_options):
if i == len(row):
painted_row = [block for block in temp_tup]
valid_options.append(painted_row)
return
if row[i] == BLACK or row[i] == WHITE:
temp_tup = temp_tup + (row[i],)
row_helper(row, temp_tup, i + 1, valid_options)
else:
temp_tup = temp_tup + (BLACK,)
row_helper(row, temp_tup, i + 1, valid_options)
temp_tup = temp_tup[:-1]
temp_tup = temp_tup + (WHITE,)
row_helper(row, temp_tup, i + 1, valid_options)
final1 = []
j = 0
lst2 = tuple()
row1 = [0,-1,-1]
row_helper(row1, lst2, j, final1)
print(final1)
help would be greatly appriciated

Matrix Rotation Unexpected Result

I am a newbie for Python, and encountered a problem about matrix rotation.
Following is my code
def rotateMatrix(matrix):
if matrix == []:
return []
row, col = len(matrix), len(matrix[0])
res = [[0]*row]*col
for i in range(row):
for j in range(col):
res[col-1-j][i] = matrix[i][j]
return res
mat = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
print rotateMatrix(mat)
The print result is [4,8,12] for all 4 rows!!! I just don't know where is the problem
This issue is with
res = [[0]*row]*col
Because you are repeating a single list col times you get this behaviour.
>>> res = [[0]*3]*4
>>> res
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> res[0][0] = 1
>>> res
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]
Which is the same as this.
>>> x = []
>>> y = x
>>> x.append(5)
>>> x
[5]
>>> y
[5]
Instead you should use list comprehension if you want a one-liner.
res = [ [ 0 for r in range(rows) ] for c in range(col) ]
Or
res = [ [ 0 ] * rows for c in range(col) ]

Calculating The sum of SandPiles

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

Print recursion steps

I would like to print the steps my program made and put these steps in a list. But i can't figure out why my code prints the wrong output. I am new to programming and i hope somoene could help. This is my code:
r=[]
listOfsteps = []
j = 0
class Main(object):
def __init__(self):
i=0
while i != 1:
self.method(r, j)
i+=1
def method(self, r, j):
r.append(j)
listOfsteps.append(r)
j+=1
if j ==5:
return "stop"
print r
print "ListOfSteps", listOfsteps
return self.method(r, j)
Main()
Output now:
[0]
ListOfSteps [[0]]
[0, 1]
ListOfSteps [[0, 1], [0, 1]]
[0, 1, 2]
ListOfSteps [[0, 1, 2], [0, 1, 2], [0, 1, 2]]
[0, 1, 2, 3]
ListOfSteps [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
Output that I want:
[0]
ListOfSteps [[0]]
[0, 1]
ListOfSteps [[0], [0, 1]]
[0, 1, 2]
ListOfSteps [[0], [0, 1], [0, 1, 2]]
[0, 1, 2, 3]
ListOfSteps [[0], [0, 1], [0, 1, 2], [0, 1, 2, 3]]
Use:
listOfsteps.append(list(r))
Instead of:
listOfsteps.append(r)
in your version you append a reference to r and in the next iteration you change r so the reference you have stored is affected. You need to copy a list you want to append.
You could also use copy for doing this.
r=[]
listOfsteps = []
j = 0
class Main(object):
def __init__(self):
#you don't need loop while for your example
self.method(r, j)
def method(self, r, j):
r.append(j)
# append only the steps index
#you don't need to add whole list for every step
listOfsteps.append(j)
j+=1
if j == 5:
return "stop"
print r
#to print your step with your output that you want use this loop
l = [listOfsteps[:i+1] for i in range(len(listOfsteps))]
print "ListOfSteps", l
return self.method(r, j)
Main()

Categories

Resources