What does this list comprehension do? - python

dp = [[0 for x in range(m+1)] for x in range(n+1)]
Can someone explain this code what actually happens in this part of the code? I think this involves list comprehensions.

dp = [[0 for x in range(m+1)] for x in range(n+1)]
This is equivalent to
for x in range(n+1):
for x in range(m+1):
dp = 0
This will create a 2D array of size (n + 1) x (m + 1). Suppose, n = 2, and m = 3. Then, the outer loop will run for 3 times, and for each time the outer loop runs, the inner loop will run 4 times. So, it will make a list [0 0 0 0]```` (in the inner loop). Now, as the inner loop is executing thrice, there will be 3 lists[0 0 0 0] [0 0 0 0] [0 0 0 0]```, and they will altogether form a 3 x 4 matrix.
This can be better understood as
for x in range(3):
for x in range(4):
print(0, end = ' ')
print()
The above snippet outputs
0 0 0 0
0 0 0 0
0 0 0 0

Basically dp will be a 2D-Matrix of dimension(n+1,m+1).
[0 for x in range(m+1)] : this create a list of size (m+1) initialized with zeros.
For example: if m=2, list will be [0,0,0]
[[0 for x in range(m+1)] for x in range(n+1)] : Now when we see the whole code
together, we will get a 2D list.
For example, if n=2, dp will be [[0,0,0], [0,0,0], [0,0,0]]

Related

Python 9x9 and 3x3 array validation excluding 0

I am trying to validate if any numbers are duplicates in a 9x9 array however need to exclude all 0 as they are the once I will solve later. I have a 9x9 array and would like to validate if there are any duplicates in the rows and columns however excluding all 0 from the check only numbers from 1 to 9 only. The input array as example would be:
[[1 0 0 7 0 0 0 0 0]
[0 3 2 0 0 0 0 0 0]
[0 0 0 6 0 0 0 0 0]
[0 8 0 0 0 2 0 7 0]
[5 0 7 0 0 1 0 0 0]
[0 0 0 0 0 3 6 1 0]
[7 0 0 0 0 0 2 0 9]
[0 0 0 0 5 0 0 0 0]
[3 0 0 0 0 4 0 0 5]]
Here is where I am currently with my code for this:
#Checking Columns
for c in range(9):
line = (test[:,c])
print(np.unique(line).shape == line.shape)
#Checking Rows
for r in range(9):
line = (test[r,:])
print(np.unique(line).shape == line.shape)
Then I would like to do the exact same for the 3x3 sub arrays in the 9x9 array. Again I need to somehow exclude the 0 from the check. Here is the code I currently have:
for r0 in range(3,9,3):
for c0 in range(3,9,3):
test1 = test[:r0,:c0]
for r in range(3):
line = (test1[r,:])
print(np.unique(line).shape == line.shape)
for c in range(3):
line = (test1[:,c])
print(np.unique(line).shape == line.shape)
``
I would truly appreciate assistance in this regard.
It sure sounds like you're trying to verify the input of a Sudoku board.
You can extract a box as:
for r0 in range(0, 9, 3):
for c0 in range(0, 9, 3):
box = test1[r0:r0+3, c0:c0+3]
... test that np.unique(box) has 9 elements...
Note that this is only about how to extract the elements of the box. You still haven't done anything about removing the zeros, here or on the rows and columns.
Given a box/row/column, you then want something like:
nonzeros = [x for x in box.flatten() if x != 0]
assert len(nonzeros) == len(set(nonzeros))
There may be a more numpy-friendly way to do this, but this should be fast enough.
Excluding zeros is fairly straight forward by masking the array
test = np.array(test)
non_zero_mask = (test != 0)
At this point you can either check the whole matrix for uniqueness
np.unique(test[non_zero_mask])
or you can do it for individual rows/columns
non_zero_row_0 = test[0, non_zero_mask[0]]
unique_0 = np.unique(non_zero_row_0)
You can add the logic above into a loop to get the behavior you want
As for the 3x3 subarrays, you can loop through them as you did in your example.
When you have a small collection of things (small being <=64 or 128, depending on architecture), you can turn it into a set using bits. So for example:
bits = ((2**board) >> 1).astype(np.uint16)
Notice that you have to use right shift after the fact rather than pre-subtracting 1 from board to cleanly handle zeros.
You can now compute three types of sets. Each set is the bitwise OR of bits in a particular arrangement. For this example, you can use sum just the same:
rows = bits.sum(axis=1)
cols = bits.sum(axis=0)
blocks = bits.reshape(3, 3, 3, 3).sum(axis=(1, 3))
Now all you have to do is compare the bit counts of each number to the number of non-zero elements. They will be equal if and only if there are no duplicates. Duplicates will cause the bit count to be smaller.
There are pretty efficient algorithms for counting bits, especially for something as small as a uint16. Here is an example: How to count the number of set bits in a 32-bit integer?. I've adapted it for the smaller size and numpy here:
def count_bits16(arr):
count = arr - ((arr >> 1) & 0x5555)
count = (count & 0x3333) + ((count >> 2) & 0x3333)
return (count * 0x0101) >> 8
This is the count of unique elements for each of the configurations. You need to compare it to the number of non-zero elements. The following boolean will tell you if the board is valid:
count_bits16(rows) == np.count_nonzero(board, axis=1) and \
count_bits16(cols) == np.count_nonzero(board, axis=0) and \
count_bits16(blocks) == np.count_nonzero(board.reshape(3, 3, 3, 3), axis=(1, 3))

Trying to solve increment a double list in python by an index

I am trying to solve this problem.This is leet code 1252.
Basically you have a matrix and index.
Say you have a matrix
0 0 0
0 0 0
and you have an index
0 1
1 1
The left side of the index is which row value you increment by one and the right hand side is which columns value you increment by one.
Well the you increment the 0 row by one and the 1 row by so you get
1 1 1
1 1 1
and then you look at the let side of the index and that means you increment the 1 column by one and the one colums by one so you get
1 2 1
1 2 1
1 3 1
1 3 1
I tried to solve this with the following code
def matrix(n,m,index):
nums=[[0]*m]*n
print(nums)
a=len(nums)
b=len(nums[0])
for i in range(a):
c=index[i][0]
print("the value of c is ",c)
for j in range(b):
nums[c][j]=nums[c][j]+1
print(nums)
for j in range(a):
c=index[1][j]
print(c)
for i in range(a):
nums[i][c]=nums[i][c]+1
print(nums)
index=[[0,1],[1,1]]
n=2
m=3
matrix(n,m,index)
but I end up getting
2 6 2
2 6 2
for my input
0 0 0
0 0 0
the weird thing is Try the same code and get the correct answer.
def inc(nums):
print(nums)
a=len(nums)
b=len(nums[0])
for i in range(a):
c=index[i][0]
for j in range(b):
nums[c][j]=nums[c][j]+1
print(nums)
for j in range(a):
c=index[1][j]
print(c)
for i in range(a):
nums[i][c]=nums[i][c]+1
print(nums)
a=[[0,0,0],[0,0,0]]
index=[[0,1],[1,1]]
inc(a)
the correct answer is
1 3 1
1 3 1
Instead of instantly updating matrix, take 2 lists for row changes and column changes initialized with zero.
Traverse through index list and make changes to row and column lists:
initially
r = [0,0] , c = [0,0,0]
index -> 0 1
r = [1,0] , c = [0,1,0]
index -> 1 1
r = [1,1] , c = [0,2,0]
then, at last, you increment each row with the corresponding value in row list and same with column list.
This is an optimised solution too.
Here's my code :
n = 2
m = 3
index = [[0,1],[1,1]]
mat = [[0 for i in range(m)] for j in range(n)]
r = [0 for i in range(n)]
c = [0 for i in range(m)]
for ri,ci in index:
r[ri]+=1
c[ci]+=1
for i in range(n):
mat[i] = [r[i]]*m
for i in range(m):
if c[i]>0:
for j in range(n):
mat[j][i] += c[i]
print(mat)
Output:
[[1, 3, 1],
[1, 3, 1]]

Random double loop in Python

I would like to create a random double loop in Python.
For example, for (N,N)=(2,2) the program should give:
0 1
0 0
1 1
1 0
Or another example
0 0
1 1
1 0
0 1
So far, I have done this:
r1 = list(range(2))
r2 = list(range(2))
random.shuffle(r1)
random.shuffle(r2)
for i in r1:
for j in r2:
# Do something with i
This, however, does not give the desired result, because I want i's to be shuffled too and not give for example all (1,x) sequentially. Any ideas?
Shuffle the product of the ranges, not each individual range.
import itertools
pairs = list(itertools.product(r1, r2)) # [(i,j) for i in r1 for j in r2]
random.shuffle(pairs)
for i, j in pairs:
...

How to create lists of 3x3 sudoku block in python

I need help creating a list for each of the 9 3x3 blocks in sudoku. so I have a list of lists representing the original sudoku board (zero means empty):
board=[[2,0,0,0,0,0,0,6,0],
[0,0,0,0,7,5,0,3,0],
[0,4,8,0,9,0,1,0,0],
[0,0,0,3,0,0,0,0,0],
[3,0,0,0,1,0,0,0,9],
[0,0,0,0,0,8,0,0,0],
[0,0,1,0,2,0,5,7,0],
[0,8,0,7,3,0,0,0,0],
[0,9,0,0,0,0,0,0,4]]
I need to turn these into a list of lists containing the 3x3 blocks. So for example:
[[2,0,0,0,0,0,0,4,8],[etc]]
i tried creating one list called "blocks" containing 9 other lists with just zeroes in each list. so it looked like:
blocks=[[0,0,0,0,0,0,0,0,0],[etc]
then i used a while loop to change the values in the list:
BLOCK_COUNT=0
BOARD_COUNT=0
while BLOCK_COUNT<len(blocks):
blocks[BLOCK_COUNT][0]=board[BOARD_COUNT][BOARD_COUNT]
blocks[BLOCK_COUNT][1]=board[BOARD_COUNT][BOARD_COUNT+1]
blocks[BLOCK_COUNT][2]=board[BOARD_COUNT][BOARD_COUNT+2]
blocks[BLOCK_COUNT][3]=board[BOARD_COUNT+1][BOARD_COUNT]
blocks[BLOCK_COUNT][4]=board[BOARD_COUNT+1][BOARD_COUNT+1]
blocks[BLOCK_COUNT][5]=board[BOARD_COUNT+1][BOARD_COUNT+2]
blocks[BLOCK_COUNT][6]=board[BOARD_COUNT+2][BOARD_COUNT]
blocks[BLOCK_COUNT][7]=board[BOARD_COUNT+2][BOARD_COUNT+1]
blocks[BLOCK_COUNT][8]=board[BOARD_COUNT+2][BOARD_COUNT+2]
BLOCK_COUNT+=1
BOARD_COUNT+=3
This however gives me an index error. if I create 2 of those while loops with "BLOCK_COUNT" being 3 and 6 respectively then i get a better answer but it still doesn't give me the correct 3x3 block for some. So i'm pretty much at a loss for how to do this. Thanks.
def getBlocks(board):
answer = []
for r,c in itertools.product(range(3), repeat=2):
answer.append([board[r+i][c+j] for i,j in itertools.product(range(0, 9, 3), repeat=2)])
return answer
Of course, you could replace the whole thing with just one list comprehension:
answer = [[board[r+i][c+j] for i,j in itertools.product(range(0, 9, 3), repeat=2)]
for r,c in itertools.product(range(3), repeat=2)]
In case you are interested in a version that doesn't use any built-ins to do any heavy lifting:
def getBlocks(board):
answer = []
for r in range(3):
for c in range(3):
block = []
for i in range(3):
for j in range(3):
block.append(board[3*r + i][3*c + j])
answer.append(block)
return answer
So what's happening here?:
Well, first, we decide to iterate over the 9 blocks that we want. These are governed by the r and c variables. This is also why we multiply them by 3 when we access the numbers on the board (because each block is a square of side 3).
Next, we want to iterate over the elements in each block. Translation: Lookup the numbers within each 3x3 block. The index of each element within the block is governed by i and j. So we have i and j that govern the elements we want to access, along with r and c, which are their offsets from the board itself, determining the location of the "block" we want. Now we're off to the races.
For each r and c (notice that each loops over range(3), so there are 9 (r,c) pairs - the 9 blocks that we are after), loop over the 9 elements in the block (the 9 (i,j) pairs). Now, simply access the elements based on their relative locations from the (r,c) offsets (3*r gives the first row of the relevant block, and adding i gives the row of the required element. Similarly, 3*c gives the first column of the relevant block, and adding j gives the column of the required element. Thus, we have the coordinates of the element we want). Now, we add the element to block.
Once we've looped over all the elements in the block, we add the block itself to the answer, and presto! we're done
You can do this with a combination of reshape and transpose when you use numpy.
edit - sorry - hit enter too soon:
import numpy as np
board=[[2,0,0,0,0,0,0,6,0],
[0,0,0,0,7,5,0,3,0],
[0,4,8,0,9,0,1,0,0],
[0,0,0,3,0,0,0,0,0],
[3,0,0,0,1,0,0,0,9],
[0,0,0,0,0,8,0,0,0],
[0,0,1,0,2,0,5,7,0],
[0,8,0,7,3,0,0,0,0],
[0,9,0,0,0,0,0,0,4]]
t = np.array(board).reshape((3,3,3,3)).transpose((0,2,1,3)).reshape((9,9));
print t
Output:
[[2 0 0 0 0 0 0 4 8]
[0 0 0 0 7 5 0 9 0]
[0 6 0 0 3 0 1 0 0]
[0 0 0 3 0 0 0 0 0]
[3 0 0 0 1 0 0 0 8]
[0 0 0 0 0 9 0 0 0]
[0 0 1 0 8 0 0 9 0]
[0 2 0 7 3 0 0 0 0]
[5 7 0 0 0 0 0 0 4]]
should work, in python3 you might replace "(m/3)*3" with "int(m/3)*3"
[[board[(m/3)*3+i][(m%3)*3+j] for i in range(3) for j in range(3)] for m in range(9)]
this uses no builtins and is faster 3 nested for loops
def get_boxes(board):
boxes = []
for i in range(9):
if i == 0 or i % 3 == 0:
box_set_1 = board[i][:3] + board[i + 1][:3] + board[i + 2][:3]
boxes.append(box_set_1)
box_set_2 = board[i][3:6] + board[i + 1][3:6] + board[i + 2][3:6]
boxes.append(box_set_2)
box_set_3 = board[i][6:] + board[i + 1][6:] + board[i + 2][6:]
boxes.append(box_set_3)
def get_boxes(board):
boxes = []
for i in range(9):
if i == 0 or i % 3 == 0:
box_set_1 = board[i][:3] + board[i + 1][:3] + board[i + 2][:3]
boxes.append(box_set_1)
box_set_2 = board[i][3:6] + board[i + 1][3:6] + board[i + 2][3:6]
boxes.append(box_set_2)
box_set_3 = board[i][6:] + board[i + 1][6:] + board[i + 2][6:]
boxes.append(box_set_3)
return boxes

Using `for` in `range(x)` loop

Shouldn't both blocks of code print similar results? Why is the range function inside of the inner loop reevaluated each time the inner for statement is reached while the range function in the outerloop is only evaluated once?
x = 4
for j in range(x)
for i in range(x)
print i
x = 2
Results
0
1
2
3
0
1
0
1
0
1
I know the first 4 integers printed ( 0 - 3) are a result of the code
for j in range(x): code but why are the the following also printed?
0
1
0
1
0
1
The code
x = 4
for j in range(x):
print i
x = 5
Prints
0 1 2 3
Additional Info
Python 2.7 in IDLE
I can only explain by walking through the iterations of the loops, so here goes:
x = 4
for j in range(x)
for i in range(x)
print i
x = 2
First time through.
x = 4
for j in [0, 1, 2, 3]
for i in range [0, 1, 2, 3]
print i
x = 2
prints
0
1
2
3
Now x is set as 2, but the outer loops range has already been executed, so it is not reevaluated.
Code now becomes:
for j in [0, 1, 2, 3]:
for i in [0, 1]:
print i
x = 2
prints
0
1
And this continues two more times.
Function range(x) produces a list of [0,1,2,3,4]. In for loop you iterate over this list.
Your code is equivalent to:
for j in [0,1,2,3]:
for i in [0,1,2,3]:
print i
for i in [0,1]:
print i
for i in [0,1]:
print i
for i in [0,1]:
print i
range(x) is evaluated only once i.e. when the loop begins, that is why modifying x inside the loop has no effect.
However, in the first code clock, you change x to 2 in the inner, so the next time the inner loop is executed, range only gives (0,1).
Edit: your first block of code is equivalent to
x = 5
for i in range(x)
print i
x = 2
Here is how I view it:
Inner loop is executed for each iteration of outer loop
x = 4
j = 0
for i in range (x):
print(i)
x = 2
j = 1
for i in range(x) # this x is no longer 4 but it is 2
print(i)
x = 2
j = 2
for i in range (x): # this x is, of course, 2
print(i)
x = 2
j = 3
for i in range (x): # this x is, of course, 2
print(i)
x = 2
j is not printed, insert " print('xx', j, 'oo') " before " for i in range(x): "
then change to "print('xx', x, 'oo')
or change 'for j in range(x):' to 'for j in range(225,200,-5):' follow with 'print(j)' before 'for i in range(x):'

Categories