Related
I'm adapting code I have C to Python. I would like to re-write this piece of my code using the functional paradigm in Python. My current code:
X = [0, 1, 2, 3, 4, 3, 2, 2, 3, 3, 2, 3, 3, 3, 2, 3, 2, 1, 1, 4, 3, 4, 4, 5, 1, 4, 2, 3, 3, 3, 2, 4, 4, 1, 3, 3, 2, 4, 1, 3, 3, 5, 5, 4, 4, 3, 2, 3, 4, 2, 1, 3, 4, 1, 2, 3, 5, 2, 3, 4, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 4, 3, 1, 3, 3, 3, 2, 3, 5, 2, 1, 2, 3, 2, 1, 4, 1, 3, 2, 1, 3, 2, 3, 5, 2, 4, 1, 3, 4, 3, 3, 2, 4, 3, 4, 4, 3, 2, 1, 2, 3, 3, 4, 1, 4, 4, 3, 3, 3, 4, 3]
res = [0] * 121
for i in range(1, 31):
k = 0
for _ in range(0, 4):
res[i] += X[i + k]
k = k + 30
print(res)
How can I make this more Pythonic? Here reproduce a necessary scale in my algorithm with the following output:
[0, 9, 12, 11, 12, 13, 7, 12, 11, 12, 12, 13, 13, 13, 13, 13, 9, 9, 11, 10, 8, 12, 15, 9, 8, 15, 11, 11, 11, 12, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Thanks,
EDMC.
You might consider re-thinking your code as it basically re-assigns the zero-filled list of the length of the input list.
That shall be the thing that, to my current understanding, protects your code from being re-written in functional style.
However, packed your loop into more compact form:
for j in range(30):
for i in range(4):
res[1 + j] += X[1 + i * 30 + j]
UPD: After Re-Thinking This, Came up with the Following:
Suggest dropping the leading 0 as it does not seemingly bear any meaningful data:
X.pop(0)
Then, construct res without those trailing 0-s in functional style as desired:
res = [sum(X[_::30]) for _ in range(30)]
Trust that solves your task.
I have the written the code below, it's not ready yet but I ran into problems when testing it. The goal is to check whether or not numbers 1 to 9 appear more than once in one single row:
def rivi_oikein(sudoku: list, rivi_nro: int):
unique_list = [] #4
row = sudoku[rivi_nro]
zeros = row.count(0) #6
others = len(unique_list)
for i in row:
if i not in unique_list:
unique_list.append(i)
print(unique_list) # prints -> [9, 0, 8, 3]
print(row) # prints -> [9, 0, 0, 0, 8, 0, 3, 0, 0]
print(others) # prints -> 0
print(zeros) # prints -> 6
if __name__ == "__main__":
sudoku = [
[9, 0, 0, 0, 8, 0, 3, 0, 0],
[2, 0, 0, 2, 5, 0, 7, 0, 0],
[0, 2, 0, 3, 0, 0, 0, 0, 4],
[2, 9, 4, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 7, 3, 0, 5, 6, 0],
[7, 0, 5, 0, 6, 0, 4, 0, 0],
[0, 0, 7, 8, 0, 3, 9, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 3],
[3, 0, 0, 0, 0, 0, 0, 0, 2]
]
print(rivi_oikein(sudoku, 0))
enter code here
What confuses me is the "print(others) as it's supposed to be "len(unique_list)" which contains 4 numbers. Why the len() isn't working?
Sorry for the bad indent. I can't figure out how to copy+paste it correctly.
When you run others = len(unique_list), the length of unique_list really is 0. This syntax doesn't forever bind the variable others to the length of unique_list; it just grabs whatever that length is at the moment of running that instruction, and stores it (as a number, completely independent from unique_list henceforth) within others, so that's what you're seeing.
You could, for instance, print(len(unique_list)) instead if what you want is to find the length of it at the time of printing; or, if you do want to store it as well, assign that value when it makes sense (i.e, when the list is at the state you wish to sample):
others = len(unique_list)
print(others)
or some such thing.
This question already has answers here:
python .count for multidimensional arrays (list of lists)
(3 answers)
Closed 1 year ago.
def count(matrix: list, number: int):
count([[1, 4, 0, 0, 6, 3], [0, 3, 4, 0, 0, 0], [0, 0, 5, 6, 0]], 0)
I am trying to make function that counts all zeros or any other number from matrix list but for now its 0.
try this:
def count(matrix: list, number: int):
return sum(l.count(number) for l in matrix)
count([[1, 4, 0, 0, 6, 3], [0, 3, 4, 0, 0, 0], [0, 0, 5, 6, 0]], 0)
# 9
count([[1, 4, 0, 0, 6, 3], [0, 3, 4, 0, 0, 0], [0, 0, 5, 6, 0]], 6)
# 2
import itertools
def count(matrix: list, number: int):
return list(itertools.chain.from_iterable(matrix)).count(number)
count([[1, 4, 0, 0, 6, 3], [0, 3, 4, 0, 0, 0], [0, 0, 5, 6, 0]], 0)
9
I'm making a sudoku solving program in Python.
I have a class, an inner class, a list, constructors and a function that would make the list of Row objects.
class Table:
rows = []
def __init__(self):
initRows()
class Row:
numbers = []
def __init__(self):
"stuff that stores a list of integers in **numbers** list"
def initRows(self, numbers):
for i in range(9):
temp_row = self.Row(i, numbers)
self.rows.append(temp_row)
The program goes like this:
When a Table object is created it automatically tries to make a 9 length list of Row objects with the initRows() function.
In the initRows() function we just create a temporary object of class Row and instantly append() it to the rows list.
When we create a Row object it just stores the given numbers for the given row of the sudoku table.
If I print() the numbers list of each temporary Row object after it is created then it gives the correct values.
[0, 0, 0, 7, 4, 0, 0, 0, 6]
[4, 0, 6, 8, 0, 0, 5, 0, 7]
[7, 0, 0, 0, 9, 0, 0, 0, 4]
[0, 3, 0, 9, 8, 4, 7, 0, 0]
[8, 2, 0, 6, 1, 3, 4, 0, 9]
[0, 4, 0, 0, 0, 0, 3, 0, 0]
[0, 6, 2, 3, 7, 0, 0, 0, 5]
[0, 0, 5, 4, 0, 9, 0, 0, 0]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
But when I try to print() the values of each Row object after the for loop loops once or more or after the initialization is finished then the list is filled with only the last Row object
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
[0, 7, 0, 0, 6, 1, 2, 0, 8]
I was searching on the internet for hours and found that people have issues with the append() function of the list class but nothing helped.
So my question is: How could I make this work?
(If any other information/part of code is needed: ask away!)
It turns out in the Row class the numbers list was a class attribute (means it's shared across all objects of the Row class) rather than an instance attribute.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I wrote a backtracking Sudoku solving algorithm in Python.
It solves a 2D array like this (zero means "empty field"):
[
[7, 0, 0, 0, 0, 9, 0, 0, 3],
[0, 9, 0, 1, 0, 0, 8, 0, 0],
[0, 1, 0, 0, 0, 7, 0, 0, 0],
[0, 3, 0, 4, 0, 0, 0, 8, 0],
[6, 0, 0, 0, 8, 0, 0, 0, 1],
[0, 7, 0, 0, 0, 2, 0, 3, 0],
[0, 0, 0, 5, 0, 0, 0, 1, 0],
[0, 0, 4, 0, 0, 3, 0, 9, 0],
[5, 0, 0, 7, 0, 0, 0, 0, 2],
]
like this:
[
[7, 5, 8, 2, 4, 9, 1, 6, 3],
[4, 9, 3, 1, 5, 6, 8, 2, 7],
[2, 1, 6, 8, 3, 7, 4, 5, 9],
[9, 3, 5, 4, 7, 1, 2, 8, 6],
[6, 4, 2, 3, 8, 5, 9, 7, 1],
[8, 7, 1, 9, 6, 2, 5, 3, 4],
[3, 2, 7, 5, 9, 4, 6, 1, 8],
[1, 8, 4, 6, 2, 3, 7, 9, 5],
[5, 6, 9, 7, 1, 8, 3, 4, 2]
]
But for "hard" Sudokus (where there are a lot of zeros at the beginning), it's quite slow. It takes the algorithm around 9 seconds to solve the Sudoku above. That's a lot better then what I startet with (90 seconds), but still slow.
I think that the "deepcopy" can somehow be improved/replaced (because it is executed 103.073 times in the example below), but my basic approaches were slower..
I heard of 0.01 second C/C++ solutions but I'm not sure if those are backtracking algorithms of some kind of mathematical solution...
This is my whole algorithm with 2 example Sudokus:
from copy import deepcopy
def is_sol_row(mat,row,val):
m = len(mat)
for i in range(m):
if mat[row][i] == val:
return False
return True
def is_sol_col(mat,col,val):
m = len(mat)
for i in range(m):
if mat[i][col] == val:
return False
return True
def is_sol_block(mat,row,col,val):
rainbow = [0,0,0,3,3,3,6,6,6]
i = rainbow[row]
j = rainbow[col]
elements = {
mat[i + 0][j + 0], mat[i + 1][j + 0], mat[i + 2][j + 0],
mat[i + 0][j + 1], mat[i + 1][j + 1], mat[i + 2][j + 1],
mat[i + 0][j + 2], mat[i + 1][j + 2], mat[i + 2][j + 2],
}
if val in elements:
return False
return True
def is_sol(mat,row,col,val):
return is_sol_row(mat,row,val) and is_sol_col(mat,col,val) and is_sol_block(mat,row,col,val)
def findAllZeroIndizes(mat):
m = len(mat)
indizes = []
for i in range(m):
for j in range(m):
if mat[i][j] == 0:
indizes.append((i,j))
return indizes
def sudoku(mat):
q = [(mat,0)]
zeroIndizes = findAllZeroIndizes(mat)
while q:
t,numSolvedIndizes = q.pop()
if numSolvedIndizes == len(zeroIndizes):
return t
else:
i,j = zeroIndizes[numSolvedIndizes]
for k in range(1,10):
if is_sol(t,i,j,k):
newt = deepcopy(t)
newt[i][j] = k
q.append((newt,numSolvedIndizes+1))
return False
mat = [
[7, 0, 0, 0, 0, 9, 0, 0, 3],
[0, 9, 0, 1, 0, 0, 8, 0, 0],
[0, 1, 0, 0, 0, 7, 0, 0, 0],
[0, 3, 0, 4, 0, 0, 0, 8, 0],
[6, 0, 0, 0, 8, 0, 0, 0, 1],
[0, 7, 0, 0, 0, 2, 0, 3, 0],
[0, 0, 0, 5, 0, 0, 0, 1, 0],
[0, 0, 4, 0, 0, 3, 0, 9, 0],
[5, 0, 0, 7, 0, 0, 0, 0, 2],
]
# mat = [
# [3, 0, 6, 5, 0, 8, 4, 0, 0],
# [5, 2, 0, 0, 0, 0, 0, 0, 0],
# [0, 8, 7, 0, 0, 0, 0, 3, 1],
# [0, 0, 3, 0, 1, 0, 0, 8, 0],
# [9, 0, 0, 8, 6, 3, 0, 0, 5],
# [0, 5, 0, 0, 9, 0, 6, 0, 0],
# [1, 3, 0, 0, 0, 0, 2, 5, 0],
# [0, 0, 0, 0, 0, 0, 0, 7, 4],
# [0, 0, 5, 2, 0, 6, 3, 0, 0]
# ]
print(sudoku(mat))
The largest time sink is that, for every open position, you try each of the nine digits, without learning anything about the attempts. Your test grid has 56 open grid locations, so anything you do is magnified through that lens. A little preprocessing will go a long way. For instance, make a list of available numbers in each row and column. Key that appropriately, and use that for your search instead of range(m).
Another technique is to apply simple algorithms to make trivial placements as they become available. For instance, you can quickly derive the 1 in the upper-left block, and the missing 7s in the left and middle columns of blocks. This alone cuts the solution time in half. Wherever you're down to a single choice for what number goes in a selected open square, or where a selected number can be placed in a particular row/col/block, then make that placement before you engage in exhaustive backtracking.