Python Variable starting point for nested for loop - python

I am attempting to create a nested for loop where the inner loop will have a different range the first time the loop runs and then use a different range for each subsequent loop.
The program is a sudoku solver. And it works by taking a position on the 9x9 board (board[k][l]), checking a condition, and then moving to the board position directly to the left (board[k][l-1]).
If l is 0 than we need to move to the previous row (k-1) and the farthest position to the right where l equals 8.
The problem I am having is on the first iteration of the inner loop the loop will not always begin with l equal to 8.
For example a user my select the square board[3][3].
The function should then check board[3][2]
then board[3][1]
then board[3][0]
then board[2][8]
etc.
The code below only works if l=8
for i in range(k, -1, -1):
for j in range(l, -1, -1):
For clarity, I can achieve the desired result using multiple for loops, but I am trying to make this code more concise:
k = user selection
l = user selection
for j in range(l, 0, -1):
test(k,j)
for i in range(k-1, -1, -1):
for j in range(9, 0 , -1):
test(i,j)
I don't like this for two reasons, first we encounter a problem if either k or l starts at 0, second it seems unnecessary to use two for loops here.

Isn't it just a matter of putting an if statement in there?
>>> k = 8
>>> l = 3
>>> run_one = True
>>> for i in range(k, -1, -1):
... if run_one:
... run_one = False
... for j in range(l, -1, -1):
... print(i, j)
... else:
... for j in range(8, -1, -1):
... print(i, j)
...
8 3
8 2
8 1
8 0
7 8
7 7
7 6
7 5
7 4
7 3
7 2
7 1
7 0
6 8
6 7
6 6
6 5
6 4
6 3
6 2
6 1
6 0
5 8
5 7
5 6
5 5
5 4
5 3
5 2
5 1
5 0
4 8
4 7
4 6
4 5
4 4
4 3
4 2
4 1
4 0
3 8
3 7
3 6
3 5
3 4
3 3
3 2
3 1
3 0
2 8
2 7
2 6
2 5
2 4
2 3
2 2
2 1
2 0
1 8
1 7
1 6
1 5
1 4
1 3
1 2
1 1
1 0
0 8
0 7
0 6
0 5
0 4
0 3
0 2
0 1
0 0
>>>

You can manage this in one single loop if you use an extra if (or a ternary expression like here):
l = 2
k = 5
for i in range(l, -1, -1):
max = k if i == l else 9
for j in range(max, 0, -1):
print("{},{}".format(i,j))
gives:
2,5
2,4
2,3
2,2
2,1
1,9
1,8
1,7
1,6
1,5
1,4
1,3
1,2
1,1
0,9
0,8
0,7
0,6
0,5
0,4
0,3
0,2
0,1

Related

How to print following pattern getting issue with spaces?

I am trying to write the code but not getting how to achieve expected output
Causing issue with space and not able to make proper judgement how to get exact spaces after every iteration
My code :
n=15
cnt=0
lst=[str(' ') for x in range(1,n+1)]
initial_length=len(''.join(lst))
print(initial_length)
for row in range(1,n+1):
lst[cnt-1]=str(row)
cnt=cnt-1
print(' '.join(lst))
Output of above code is not as expected output
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
11 10 9 8 7 6 5 4 3 2 1
12 11 10 9 8 7 6 5 4 3 2 1
13 12 11 10 9 8 7 6 5 4 3 2 1
14 13 12 11 10 9 8 7 6 5 4 3 2 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
Expected output :
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
11 10 9 8 7 6 5 4 3 2 1
12 11 10 9 8 7 6 5 4 3 2 1
13 12 11 10 9 8 7 6 5 4 3 2 1
14 13 12 11 10 9 8 7 6 5 4 3 2 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
Another approximation, by knowing the quantity of spaces in advance using a recursive function:
def findDigits(N):
if N <= 1:
return N
# Changing number to string
s = str(N)
# Add length of number to total_sum
return len(s) + findDigits(N - 1)
def print_inverse_pyramid(n):
# Calculate number of total digits until n
total_digits = findDigits(n)
# Print the pyramid
for row in range(1, n + 1):
total_digits -= len(str(row))
l_r = [str(i) for i in range(row, 0, -1)]
print(" " * (total_digits + (n - row)) + " ".join(l_r))
print_inverse_pyramid(15)
You have to account for larger digits taking up more space, which means that when creating the list that contains spaces, you need to multiply the space by how many digits are in that number which you can get by len(str(number)):
n = 15
# create a list containing how many spaces each number will take up
# in reverse order because the figure is reverse
lst = [' ' * len(str(x)) for x in range(n, 0, -1)]
# go over each number
for x in range(1, n + 1):
# replace the digit in its place from end
# by the string represantion of itself
lst[-x] = str(x)
# print joined list
print(' '.join(lst))
Also:
I strongly suggest following PEP 8 - Style Guide for Python Code. Function and variable names should be in snake_case, class names in CapitalCase. Don't have space around = if it is used as a part of keyword argument (func(arg='value')) but have space around = if it is used for assigning a value (variable = 'some value'). Have space around operators (+-/ etc.: value = x + y(except here value += x + y)). Have two blank lines around function and class declarations. Object method definitions have one blank line around them.
Quick and dirty: 'looking' at the last line
n = 15
def serie(n):
return ' '.join([str(j) for j in range(n, 0, -1)])
maxlen = len(serie(n))
for i in range(1, n +1):
s = serie(i)
print(" " * (maxlen - len(s)) + s)
With math, computing the length as the sum of the int of the log10 of values and adding for the spaces
import math
n = 15
def lenserie(n):
return sum(map(lambda i : int(math.log(i, 10)) + 1 ,range(1, n+1))) + (n-1)
maxlen = lenserie(n)
for i in range(1, n+1):
print(" " * (maxlen - lenserie(i)) + " ".join([str(i) for i in range(i, 0, -1)]))

I want to generate a new column in a pandas dataframe, counting "edges" in another column

i have a dataframe looking like this:
A B....X
1 1 A
2 2 B
3 3 A
4 6 K
5 7 B
6 8 L
7 9 M
8 1 N
9 7 B
1 6 A
7 7 A
that is, some "rising edges" occur from time to time in the column X (in this example the edge is x==B)
What I need is, a new column Y which increments every time a value of B occurs in X:
A B....X Y
1 1 A 0
2 2 B 1
3 3 A 1
4 6 K 1
5 7 B 2
6 8 L 2
7 9 M 2
8 1 N 2
9 7 B 3
1 6 A 3
7 7 A 3
In SQL I would use some trick like sum(case when x=B then 1 else 0) over ... rows between first and previous. How can I do it in Pandas?
Use cumsum
df['Y'] = (df.X == 'B').cumsum()
Out[8]:
A B X Y
0 1 1 A 0
1 2 2 B 1
2 3 3 A 1
3 4 6 K 1
4 5 7 B 2
5 6 8 L 2
6 7 9 M 2
7 8 1 N 2
8 9 7 B 3
9 1 6 A 3
10 7 7 A 3

How to add another condition to Sudoku puzzle

I have just start coding with python since fall. So i am not a professional python coder.
I have started to code a Sudoku program. And fortunately at last I could have come up with this code:
def isValid(num, x, y):
for i in range(9):
if board[i][y] == num:
return False
if board[x][i] == num:
return False
row = x - x % 3
col = y - y % 3
for i in range(3):
for j in range(3):
if board[i + row][j + col] == num:
return False
return True
def solve(remaining):
if remaining == 0:
return True
for i in range(9):
for j in range(9):
if board[i][j] != 0:
continue
for num in range(1, 10):
if isValid(num, i, j):
board[i][j] = num
if solve(remaining - 1):
return True
board[i][j] = 0
return False
return False
def pp():
for i in range(9):
for j in range(9):
print(board[i][j], end=" ")
print()
print()
board = []
remaining = 0
for i in range(9):
a=input()
a=a.split()
a = list(map(int, a))
for j in a:
if j == 0:
remaining += 1
board.append(a)
solve(remaining)
pp()
For instance I give such an input to it:
0 0 0 0 0 0 0 1 0
0 0 2 0 0 0 0 3 4
0 0 0 0 5 1 0 0 0
0 0 0 0 0 6 5 0 0
0 7 0 3 0 0 0 8 0
0 0 3 0 0 0 0 0 0
0 0 0 0 8 0 0 0 0
5 8 0 0 0 0 9 0 0
6 9 0 0 0 0 0 0 0
And this is my output:
7 4 9 2 3 8 6 1 5
1 5 2 6 9 7 8 3 4
8 3 6 4 5 1 2 7 9
2 1 8 9 7 6 5 4 3
9 7 5 3 2 4 1 8 6
4 6 3 8 1 5 7 9 2
3 2 1 5 8 9 4 6 7
5 8 4 7 6 3 9 2 1
6 9 7 1 4 2 3 5 8
Now I intend to add a new condition to this Sudoku which is can do this process for 4 more 3*3 boxes in the board like this (which is named Hyper-Sudoku):
That for my puzzle it returns:
9 4 6 8 3 2 7 1 5
1 5 2 6 9 7 8 3 4
7 3 8 4 5 1 2 9 6
8 1 9 7 2 6 5 4 3
4 7 5 3 1 9 6 8 2
2 6 3 5 4 8 1 7 9
3 2 7 9 8 5 4 6 1
5 8 4 1 6 3 9 2 7
6 9 1 2 7 4 3 5 8
Is there any way to add this option to my Sudoku or not, I have to change my whole algorithm?
Thanks for your answers.
I think your program looks great. Since you separated your isValid and solve functions it makes adding the change easier. All you will need to is modify the isValid function.
def isValid(num, x, y):
# row and column check
for i in range(9):
if board[i][y] == num:
return False
if board[x][i] == num:
return False
# 3x3 tile check
row = x - x % 3
col = y - y % 3
for i in range(3):
for j in range(3):
if board[i + row][j + col] == num:
return False
# Hypersudoku check
if x not in [0, 4, 8] and y not in [0, 4, 8]:
row = 1 if x < 4 else 5
col = 1 if y < 4 else 5
for i in range(3):
for j in range(3):
if board[i + row][j + col] == num:
return False
return True

digits 0 to 9 in a triangle

I need help with a task in my intro to python programming course that requires a code that will print the following using two 'for-loops', one being nested:
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 9
So far i have come up with the following code, but my triangle of numbers begins at the digit 1 instead of 0:
for i in range(-1,9):
print ('\n')
for i in range (int(i+1)):
j = i+1
print (j, end=' ')
Can anyone advise what I should do to make my list of digits begin from 0 instead of 1? Also any suggestions on how to make my code more readable? Thanks.
When using range, if you want the last integer to be included, you need to add one. With this in mind, I think the following makes sense:
for i in range(9+1): # +1 since you want the loop to include 9
for j in range(i+1): # +1 since you want your print to include i
print (j, end=' ')
print ('\n')
The print(\n) statement can go before or after your j for-loop, although the output will be slightly different. (Maybe because I'm used to mechanical typewrites, I think of \n as finishing a line rather than getting ready for a new one, but both are reasonable.)
I don't like the idea of starting at -1 so you can then add 1 later. It's unduly complicated, and a bad habit to start with as a beginner.
Keeping your code structure, the following will work:
for i in range(-1, 10): # you need 10 so that the triangle goes up to 9
print("\n")
for j in range(i + 1):
print(j, end=" ")
Result:
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 9

Creating a number list with nested For loops in Python

I've been working on this now for well over four hours and i've tried to check several resources.
I'm trying to get something like this:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
My current code for this is:
for i in range(10):
print(i, end = '')
for j in range(10):
print(j, end = '')
print()
which prints this:
00123456789
10123456789
20123456789
30123456789
40123456789
50123456789
60123456789
70123456789
80123456789
90123456789
So I just need to get rid of the very most left-hand side. Additionally, I'm trying to produce something that looks like this:
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 9
And I can get it from this:
triangle = ''
n = 9
for i in range(0, n+1):
triangle = triangle + (str(i))
print(triangle)
print()
for i in range(11):
for j in range(0+i):
print(j,end=" ")
print()
The problem with the first one is there isn't two for loops, one nested in the other. The problem with the second one is that I have range at 11 to get it to print to 9.
Lastly, I'm trying for this:
10
11 12
13 14 15
16 17 18 19
20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36 37
38 39 40 41 42 43 44 45
46 47 48 49 50 51 52 53 54
Which I've been getting with this:
x = 10
for i in range (10):
print (*range (x, x+i))
x += i
But I need two for loops. I feel like I'm very close, but just can't get the finished product.
Thanks.
For the first instance, try this:
print('', end = '')
For the second instance, the mistake is that you are adding 0 to the second for loop. Change it to:
for j in range(0, 1+i):
The thing with range is that it goes until one number lower. Have a look at docs
For the last one, you can use the following code, where y starts at 10.
y = 10
for i in range(0,10):
for j in range(0, i):
print(y + j, end=' ')
print('')
y += i
Issue with first code is that you are printing i , you do not need to print i . Code would be something like -
for i in range(10):
for j in range(10):
print(j, end = ' ')
print()
For the rest of the question, if you are getting the answer without nested loops, why do you need nested loops?
Here is how to go about it -
First is very simple
ht = 10
y = range(ht)
"\n".join(map(lambda x: " ".join(map(str,x)), [y]*ht))
Second one is a bit interesting
ht = 10
y = range(ht)
for i in range(1, ht+1):
print " ".join(map(str, y[0:i]))
Third one
start = 10
ht = 9
limit = (ht*(ht+1))/2 # using the sum of n to find out total elements
y = range(start, limit+1)
for i in range(1, ht+1):
print " ".join(map(str, y[0:i]))
y = y[i:]
The complicated map(str, y) is only to get a string to be printed.
Is this what you want?

Categories

Resources