So i have nested loops and array
[[0, 1], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4]]:
for x in string_list:
for y in string_list:
print(x,y)
provides me the output
[0, 1] [0, 1]
[0, 1] [0, 1, 2, 3, 4, 5, 6]
[0, 1] [0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5, 6] [0, 1]
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4]
[0, 1, 2, 3, 4] [0, 1]
[0, 1, 2, 3, 4] [0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4] [0, 1, 2, 3, 4]
But i have a lot of duplicates pairs and i did:
for x in range(0, len(string_list)):
for y in range(x+1, len(string_list)):
print(x,y, string_list)
but it's working only for 2 digit pairs.
So what i want is:
[0, 1] [0, 1]
[0, 1] [0, 1, 2, 3, 4, 5, 6]
[0, 1] [0, 1, 2, 3, 4]
**[0, 1, 2, 3, 4, 5, 6] [0, 1]** // avoid to output that pair cause we had that one
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4]
[0, 1, 2, 3, 4] [0, 1]
**[0, 1, 2, 3, 4] [0, 1, 2, 3, 4, 5, 6]** // avoid to output that pair cause we had that one
[0, 1, 2, 3, 4] [0, 1, 2, 3, 4]
does it possible to do without using itertools ?
Thank you!
for k, x in enumerate(string_list):
for y in string_list[k:]:
print(x,y)
You can use itertools.combinations:
for x, y in it.combinations(string_list, 2):
# process x, y
Obviously using itertools.combinations is ideal, but since you said you don't want to use itertools, you could use a set comprehension to build the set of unique combinations (you have to convert the lists to tuples to make them hashable), then convert them back to lists as needed:
[list(list(t) for t in f) for f in {
frozenset((tuple(x), tuple(y))) for y in string_list for x in string_list
}]
You can put a continue statement in the inner loop to skip duplicates:
for x in string_list:
for y in string_list:
if x == y:
continue
print(x,y)
I had an idea a while ago of making a program that would solve a Sudoku board, so I made the code below. The code receives as input a 9x9 integer list, where an incomplete cell is represented by the number 0.
def checkSolutions(grid, i, j):
"""
Given a Sudoku board and the position of an
incomplete cell, it returns a list with all
the possible numbers that this position can occupy.
"""
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9]
solutions = []
solutions1x9 = [grid[x][j] for x in range(9)]
solutions9x1 = [grid[i][x] for x in range(9)]
rowGrid = i // 3
columnGrid = j // 3
solutions3x3 = [grid[i][j] for i in range(3*rowGrid, 3*rowGrid+3)
for j in range(3*columnGrid, 3*columnGrid+3)]
solutions = solutions + [i for i in digits if i not in solutions1x9]
solutions = solutions + [i for i in digits if i not in solutions9x1]
solutions = solutions + [i for i in digits if i not in solutions3x3]
solutions = list(set(solutions))
solutions = [i for i in solutions if i not in solutions1x9]
solutions = [i for i in solutions if i not in solutions9x1]
solutions = [i for i in solutions if i not in solutions3x3]
return solutions
def checkSudoku(grid):
"""
Given a Sudoku board, it returns True if it is
a board that follows the rules of the game and
returns False otherwise.
"""
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for i in range(9):
if sorted(grid[i]) != digits:
return False
for i in range(9):
column = [grid[j][i] for j in range(9)]
if sorted(column) != digits:
return False
for i in range(3):
for j in range(3):
grid3x3 = [grid[x][y] for x in range(3*i, 3*i+3)
for y in range(3*j, 3*j+3)]
if sorted(grid3x3) != digits:
return False
return True
def sudoku(grid):
"""
Given an incomplete Sudoku board, it prints on
the screen the solution of that game.
"""
for i in range(9):
for j in range(9):
if grid[i][j] == 0:
solutions = checkSolutions(grid, i, j)
if len(solutions) == 1:
grid[i][j] = solutions[0]
continue
for k in solutions:
auxGrid = [x.copy() for x in grid]
auxGrid[i][j] = k
sudoku(auxGrid)
if checkSudoku(grid):
print(grid)
My problem is: if the function sudoku receives as input the following list
grid1 = [[0, 3, 7, 6, 0, 1, 5, 8, 4],
[8, 0, 0, 3, 0, 4, 9, 2, 0],
[6, 0, 9, 2, 5, 0, 3, 7, 1],
[9, 8, 0, 5, 6, 7, 1, 0, 0],
[0, 6, 0, 4, 1, 2, 0, 9, 0],
[0, 0, 1, 8, 3, 9, 0, 6, 5],
[7, 9, 6, 0, 4, 3, 8, 0, 2],
[0, 5, 8, 7, 0, 6, 0, 0, 9],
[1, 2, 4, 9, 0, 5, 6, 3, 0]]
it returns the result in less than one second, which is
[[2, 3, 7, 6, 9, 1, 5, 8, 4],
[8, 1, 5, 3, 7, 4, 9, 2, 6],
[6, 4, 9, 2, 5, 8, 3, 7, 1],
[9, 8, 2, 5, 6, 7, 1, 4, 3],
[5, 6, 3, 4, 1, 2, 7, 9, 8],
[4, 7, 1, 8, 3, 9, 2, 6, 5],
[7, 9, 6, 1, 4, 3, 8, 5, 2],
[3, 5, 8, 7, 2, 6, 4, 1, 9],
[1, 2, 4, 9, 8, 5, 6, 3, 7]]
But if it receives as input the list:
grid2 = [[1, 6, 8, 0, 0, 0, 9, 0, 2],
[0, 0, 0, 3, 0, 1, 0, 0, 0],
[0, 3, 0, 6, 2, 0, 0, 0, 0],
[0, 0, 9, 0, 0, 0, 1, 0, 6],
[0, 0, 1, 0, 0, 0, 3, 7, 0],
[0, 4, 3, 5, 0, 0, 0, 0, 9],
[0, 0, 0, 8, 0, 2, 6, 0, 0],
[0, 0, 0, 9, 0, 5, 0, 2, 3],
[2, 0, 6, 0, 3, 0, 7, 0, 0]]
it should returns
[[1, 6, 8, 4, 5, 7, 9, 3, 2],
[5, 7, 2, 3, 9, 1, 4, 6, 8],
[9, 3, 4, 6, 2, 8, 5, 1, 7],
[8, 2, 9, 7, 4, 3, 1, 5, 6],
[6, 5, 1, 2, 8, 9, 3, 7, 4],
[7, 4, 3, 5, 1, 6, 2, 8, 9],
[3, 9, 5, 8, 7, 2, 6, 4, 1],
[4, 1, 7, 9, 6, 5, 8, 2, 3],
[2, 8, 6, 1, 3, 4, 7, 9, 5]]
but the program takes so long to run that I don't even know if it returns something (I waited 30 minutes before closing the code execution). So my doubts are:
is there a mistake in my code for certain input types?
how can I improve my code to accept entries with more empty cells?
my code works perfectly fine and is it normal to take longer for entries with more empty cells?
Thanks for any help!
You can get your program to solve the second puzzle by adding a return statement to your sudoku() function at the end of the nested loops. The code below has that fix and some other rework ideas:
DIGITS = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def checkSolutions(grid, i, j):
"""
Given a Sudoku board, and the position of an
incomplete cell, it returns a list with all
the possible numbers that can occupy this position.
"""
solutions1x9 = [grid[x][j] for x in range(9)]
solutions9x1 = [grid[i][x] for x in range(9)]
rowGrid = 3 * (i // 3)
columnGrid = 3 * (j // 3)
solutions3x3 = [grid[i][j] for i in range(rowGrid, rowGrid + 3) for j in range(columnGrid, columnGrid + 3)]
return [digit for digit in DIGITS if digit not in solutions1x9 and digit not in solutions9x1 and digit not in solutions3x3]
def checkSudoku(grid):
"""
Given a Sudoku board, it returns True if it is
a board that follows the rules of the game and
returns False otherwise.
"""
for i in range(9):
if sorted(grid[i]) != DIGITS:
return False
for j in range(9):
column = [grid[i][j] for i in range(9)]
if sorted(column) != DIGITS:
return False
for i in range(3):
for j in range(3):
grid3x3 = [grid[x][y] for x in range(3 * i, 3 * i + 3) for y in range(3 * j, 3 * j + 3)]
if sorted(grid3x3) != DIGITS:
return False
return True
def sudoku(grid):
"""
Given an incomplete Sudoku board, it prints on
the screen the solution of that game.
"""
for i in range(9):
for j in range(9):
if grid[i][j] == 0:
solutions = checkSolutions(grid, i, j)
if len(solutions) == 1:
grid[i][j] = solutions[0] # permanent change to *this* reality
continue
for k in solutions:
auxGrid = [x.copy() for x in grid] # spawn a new reality
auxGrid[i][j] = k
sudoku(auxGrid)
return # already solved it recursively or no solution in *this* reality
if checkSudoku(grid):
print(grid)
grid2 = [[1, 6, 8, 0, 0, 0, 9, 0, 2],
[0, 0, 0, 3, 0, 1, 0, 0, 0],
[0, 3, 0, 6, 2, 0, 0, 0, 0],
[0, 0, 9, 0, 0, 0, 1, 0, 6],
[0, 0, 1, 0, 0, 0, 3, 7, 0],
[0, 4, 3, 5, 0, 0, 0, 0, 9],
[0, 0, 0, 8, 0, 2, 6, 0, 0],
[0, 0, 0, 9, 0, 5, 0, 2, 3],
[2, 0, 6, 0, 3, 0, 7, 0, 0]]
sudoku(grid2)
OUTPUT
> python3 test.py
[[1, 6, 8, 4, 5, 7, 9, 3, 2],
[5, 7, 2, 3, 9, 1, 4, 6, 8],
[9, 3, 4, 6, 2, 8, 5, 1, 7],
[8, 2, 9, 7, 4, 3, 1, 5, 6],
[6, 5, 1, 2, 8, 9, 3, 7, 4],
[7, 4, 3, 5, 1, 6, 2, 8, 9],
[3, 9, 5, 8, 7, 2, 6, 4, 1],
[4, 1, 7, 9, 6, 5, 8, 2, 3],
[2, 8, 6, 1, 3, 4, 7, 9, 5]]
>
Your solver is a brute-force solver which uses few smarts about the game itself. So, I can't promise there won't be a puzzle that again takes too long to finish. A more efficient solver might try all the tricks a human would to place digits before resorting to brute-force.
The modification I made may prevent your code from finding multiple solutions if they exist.
As I commented, this is a hard sudoku, so you have to guess several cells to be able to solve it. You can check my hard sudoku solver I programmed some time ago, if that helps:
def sudoku(grid):
sudoku_dict = {}
r = 'ABCDEFGHI'
c = '123456789'
for i in range(9):
for j in range(9):
sudoku_dict[r[i]+c[j]] = str(grid[i][j]) if grid[i][j] != 0 else c
square = [[x+y for x in i for y in j] for i in ('ABC','DEF','GHI') for j in ('123','456','789')]
peers = {}
for key in sudoku_dict.keys():
value = [i for i in square if key in i][0]
row = [[x+y for x in i for y in j][0] for i in key[0] for j in c]
col = [[x+y for x in i for y in j][0] for i in r for j in key[1]]
peers[key] = set(x for x in value+row+col if x != key)
for i in range(9):
sudoku_dict = Check(sudoku_dict,peers)
sudoku_dict = search(sudoku_dict, peers)
solution = []
for i in r:
solution.append([])
for j in c:
solution[r.find(i)].append(int(sudoku_dict[i+j]))
return solution
def Check(sudoku_dict, peers):
for k,v in sudoku_dict.items():
if len(v) == 1:
for s in peers[k]:
sudoku_dict[s] = sudoku_dict[s].replace(v,'')
if len(sudoku_dict[s])==0:
return False
return sudoku_dict
def search(sudoku_dict,peers):
if Check(sudoku_dict,peers)==False:
return False
if all(len(sudoku_dict[s]) == 1 for s in sudoku_dict.keys()):
return sudoku_dict
n,s = min((len(sudoku_dict[s]), s) for s in sudoku_dict.keys() if len(sudoku_dict[s]) > 1)
res = []
for value in sudoku_dict[s]:
new_sudoku_dict = sudoku_dict.copy()
new_sudoku_dict[s] = value
ans = search(new_sudoku_dict, peers)
if ans:
res.append(ans)
if len(res) > 1:
raise Exception("Error")
elif len(res) == 1:
return res[0]
Looking for a pythonic way to repeat sequences of fixed length while incrementing the sequence digits until max length is reached.
As of now, the code uses while loop and four variables one being the list itself to complete the logic as below,
l = []
i, repeat, max_len = 0, 3, 20
while True:
if len(l) + repeat <= max_len:
l.extend([i] * repeat)
else:
repeat = max_len - len(l)
l.extend([i] * repeat)
break
i += 1
The above code produces
l = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6]
Thus, repeating a fixed length sequence of 3 units until the maximum length of 20 is reached (omit any last digits of sequence outside max_len permitted)
Is there a pythonic way of doing the same?
How about this one:
[int(i/repeat) for i in range(max_len)]
Well this will make exactly your list using list comprehension.
l = [i//(repeat) for i in range(max_len)]
# [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6]
But I think there is a bug in the original function because there should be three 5s at the end.
l = [i//(repeat) for i in range(max_len//repeat * repeat)]
# [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5]
With list comprehensions
>>> i, repeat, max_len = 0, 3, 20
>>> q = max_len//repeat
>>> [x for x in range(i, i+q) for y in range(repeat)]+[i+q for y in range(max_len%repeat)]
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6]
With a different starting value:
>>> i = 5
>>> [x for x in range(i, i+q) for y in range(repeat)]+[i+q for y in range(max_len%repeat)]
[5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11]
I'm trying to sort a list by moving through it and checking if a given element of the list is greater than the next element of the list, and if so, moving it accordingly so that the smaller number is to the left, larger to the right.
This is the code I have so far:
L = [3, 4, 1, 5, 2, 0]
for i in range(0, (len(L)-1)):
if L[i] > L[i+1]:
L[i], L[i+1] = L[i+1], L[i]
print(L)
The output of this for the three iterations are as follows:
[3, 1, 4, 5, 2, 0]
[3, 1, 4, 2, 5, 0]
[3, 1, 4, 2, 0, 5]
My goal is to get it to read [0, 1, 2, 3, 4, 5]. I realize I can just use the sorted() function but I'd prefer not to. I was thinking that I could try and iterate the for loop over the list multiple times, but I am unsure as to how to do so.
Currently you only compare each element and it's successor. However you really want to compare it to all following elements (starting with i+1 and ending with len(L)), so you need a double loop:
L = [3, 4, 1, 5, 2, 0]
for i in range(0, (len(L)-1)):
for j in range(i+1, len(L)):
if L[i] > L[j]:
L[i], L[j] = L[j], L[i]
print(L)
Which prints the following steps:
[1, 4, 3, 5, 2, 0]
[0, 4, 3, 5, 2, 1]
[0, 3, 4, 5, 2, 1]
[0, 2, 4, 5, 3, 1]
[0, 1, 4, 5, 3, 2]
[0, 1, 3, 5, 4, 2]
[0, 1, 2, 5, 4, 3]
[0, 1, 2, 4, 5, 3]
[0, 1, 2, 3, 5, 4]
[0, 1, 2, 3, 4, 5]
You could just put it inside a while loop:
L = [3, 4, 1, 5, 2, 0]
flag = True
while flag:
flag = False
for i in range(0, (len(L)-1)):
if L[i] > L[i+1]:
L[i], L[i+1] = L[i+1], L[i]
flag = True
print(L)
Output:
[3, 1, 4, 5, 2, 0]
[3, 1, 4, 2, 5, 0]
[3, 1, 4, 2, 0, 5]
[1, 3, 4, 2, 0, 5]
[1, 3, 2, 4, 0, 5]
[1, 3, 2, 0, 4, 5]
[1, 2, 3, 0, 4, 5]
[1, 2, 0, 3, 4, 5]
[1, 0, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5]