controlling with range(var) doens't work properly - python

my code looks as follows:
def rd_parse(w,i,k):
for r in list(range(k)):
j = i+1 + i+r + k-1
if np(w,i,j):
return True
elif v(w,i,j):
return True
elif np(w,i,j) and v(w,j,k):
return True
else:
return False
def np(w,i,k):
if k == i + 1 and w[i] == "Hans":
return True
else:
return False
def v(w,i,k):
if k == i + 1 and w[i] == "isst":
return True
else:
return False
a possible query:
w = ["Hans"]
rd_parse[w,0,len(w)
True
which is my expected result.
now i want to query something more complicated
w = ["Hans", "isst"]
rd_parse(w,0,len(w))
which returns False
when i use the debugger, i see that my my loop doesnt work properly. it doesnt interate properly over the list given by list(range(k)), which is in case of len(w) = 2 [0,1,2]. it only chooses r=0 and doesn't take any further steps from then.
can anyone point out why that is?
i wish you a convenient evening,
b.

return returns from the function. Why do you expect the next iteration?
If you want to return True if any element matches, only return False when none of the elements match. That is, move return False outside of the loop.

You need to move the return False outside the loop, you return after the first iteration regardless, you can also simplify your functions, you also don't need to and should not call list on range just to iterate over it:
def np(w, i, k):
return k == i + 1 and w[i] == "Hans"
def v(w, i, k):
return k == i + 1 and w[i] == "isst"
def rd_parse(w, i, k):
for r in range(k):
j = i + 1 + i + r + k - 1
if v(w, i, j) or v(w,j,k):
return True
elif np(w, i, j):
return True
return False # outside loop
if np(w,i,j) is False then np(w,i,j) and v(w,j,k) could not possibly be True and in contrast if np(w,i,j) is True then you never reach any other line.

Related

UnboundLocalError Leetcode #5. Longest Palindromic Substring

Leetocode keeps giving me this UnboundLocalError, and I don't know why...
This is my code
class Solution:
def longestPalindrome(self, s: str) -> str:
def isPalindrome(s):
if len(s) == 1:
return True
if len(s) == 2 and s[0] == s[1]:
return True
else:
if s[0] == s[-1]:
return isPalindrome(s[1:-1])
else:
return False
max_ = 0
lenght = len(s)
for i in range(lenght):
for r in range(i + 1, lenght):
if isPalindrome(s[i:r]):
len_ = r - i + 1
if len_ > max_:
max_ = len_
final = s[i:r]
return final
and the error it gives me is
UnboundLocalError: local variable 'final' referenced before assignment
return final
Can someone please help me understand why this may be occurring?
I think the problem may be given in the case where the final string is of len() = 1. In that case it might be a problem the s[i : r]
your final variable is defined inside the if block and is not visible outside. just declare it outside to get rid of this erro
class Solution:
def longestPalindrome(self, s: str) -> str:
def isPalindrome(s):
if len(s) == 1:
return True
if len(s) == 2 and s[0] == s[1]:
return True
else:
if s[0] == s[-1]:
return isPalindrome(s[1:-1])
else:
return False
max_ = 0
lenght = len(s)
final = 0 # declared final here
for i in range(lenght):
for r in range(i + 1, lenght):
if isPalindrome(s[i:r]):
len_ = r - i + 1
if len_ > max_:
max_ = len_
final = s[i:r]
return final
Testcase in which s consist of only one letter. like ("a","d") your inner for loop is not executing and hence you define final inside the if is not initialize and you are returning final hence unbound error occurs.
for ex. let's say s="s"
Dry run-:
max_ :0
lenght :1 (i.e len(s))
for i in range(1):
for j in range(1,1) (i.e when first loop iterating i=0) no inner loop run
Exit()
return Final #Unbound error
To solve this error you can initialize final outside. or you can add a condition if len(s)==1: return 1
also your code solution has time complexity O(n^2) I think it will show Time limit exceeded.

Why is it not return any sequence within the string?

So for this code I want to input any string and I want it to return true if there's a sequence of 3 same consecutive characters in n.
This code works however, it only counts the first three consecutive numbers in n, but I want it to count any sequence in n.
def consec(n):
for i in range(len(n)):
if n[i] == n[i+1] == n[i+2]:
return True
else:
return False
eg: if consec("AAABC")
it prints true
but if consec("ABCCC")
it prints false even though there are 3 consecutive characters, they just happen to be later in the string.
What should I change about this code ?
Thanks,
You can use regex to extract 3 or more consecutive characters:
import re
def check_string(text):
if re.findall(r'(\w)\1\1+', text):
return True
else:
return False
There are two problems in your code. Currently it only checks the first 3 letters because of the range being between 0 and 1. If you do some print debugging with print(n[i], n[i + 1], n[i + 2]) you will see that consec("ABCCC") will only print A B C.
The second problem is that if you fix the above mentioned problem it will still only check the first 3 letters. This is because if the "if n[i]....." isn't True, it will not go to another iteration of the for loop. Instead it will return False. This you can fix by making the function only return False if it doesnt find 3 consecutive letters in any iteration.
Im assuming this is homework so the I'm not providing working code, good luck!
your for loop only iterates one time that's why you are getting incorrect responses? Try like this:
def consec(n):
result = False
for i in range(len(n)):
if result:
return result
if n[i] == n[i + 1] == n[i + 2]:
result = True
else:
result = False
return result
By this the loop will only stop if there are consecutive 3 characters or all characters are already iterated.
Move return False to outside of the loop and check reversely from the last index to avoid index error:
def consec(n):
for i in range(len(n)):
if n[i] == n[i-1] == n[i-2]:
return True
return False
Or add -2 in range(len(n):
def consec(n):
for i in range(len(n)-2):
if n[i] == n[i+1] == n[i+2]:
return True
return False
You can also use any():
def consec(n):
return any(n[i] == n[i-1] == n[i-2] for i in range(len(n)))
Or
def consec(n):
return any(n[i] == n[i+1] == n[i+2] for i in range(len(n)-2))

Python script "generating" "None" values

So I have been having this issue with a simple python script I'm working on for an assignment. I am to make a small script simulating a lottery, and have written this code:
import random
def drawNumbers(nlist, n):
drawnlist = []
i = 0
while i < n:
if i == 0:
drawnlist.append(nlist[random.randint(0,33)])
i+=1
else:
r = random.randint(0,33)
dup = False
for x in drawnlist:
if x == r:
dup = True
if dup == False:
drawnlist.append(nlist[r])
i+=1
return drawnlist
def compList(drawlist, guesslist):
count = 0
for j in drawlist:
for h in guesslist:
if j == h:
count +=1
return count
def winnings(right, altright):
altcorrect = False
if altright > 0:
altcorrect = True
if right == 7:
return 2749455
elif right == 6:
if altcorrect:
return 102110
else:
return 3385
elif right == 5:
return 95
elif right == 4:
if altcorrect:
return 45
else:
return 0
a=0
tot = 0
while a <100:
numbers = []
i = 1
while i <= 34:
numbers.append(i)
i+=1
myGuess = []
i = 0
while i <7:
if i == 0:
myGuess.append(random.randint(1,34))
i+=1
else:
r = random.randint(1,34)
dup = False
for x in myGuess:
if x == r:
dup = True
if dup == False:
myGuess.append(r)
i+=1
tot += winnings(compList(drawNumbers(numbers,7),myGuess),compList(drawNumbers(numbers,3),myGuess))
a+=1
print(tot)
And it seems to be working fine for one iteration, however, when I increase a like now with a value of 100, I get an error saying that I cannot sum an "int" object and a "None" objects. When I tinkered with the code and printed "winnings" instead of the summed total for each iteration, it looks like the function sometimes returns "None" instead of a number. I can however not seem to recreate that with a smaller amount of iterations, so my question: Is this code related, or might it be that by calling the functions "too fast" it does not create a number? I know this question might seem odd, but I am new to programming as a whole and python itself, and I have no clue how to debug this.
The winnings function can return None as there is no else to the inner if. In this case, it does not trigger the final else and returns None by default. To fix it, add an else to the if, or just remove the final else in winnings:
def winnings(right, altright):
altcorrect = False
# ...
elif right == 4:
if altcorrect:
return 45
# maybe add an else here?
# or if you get to this point, _always_ return 0
return 0
Your winnings function sometimes returns None. It's because it's not catching some cases. Python returns None if it reaches the end of a function without any other returns being hit.
Specifically, if right is 4 and altright is 0, none of the if cases will get caught and the function returns None.

Error: Unsupported Operand Types

I'm trying to use recursion to return the dot product of two lists, and I'm trying to account for the situation in which I get two lists of different length: I return 0. However, when I try to check for that condition, I get the error: unsupported operand type(s) for &: 'list' and 'list'. Why can't I use the '&' operand for two lists in Python?
def dot(L, K):
if L+K == []:
return 0
elif L == [] & K != []:
return 0
elif K == [] & L != []:
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
I would probably do something like this:
def dot(L, K):
if L + K == [] or len(L) != len(K): # this only needs to be checked once
return 0
return dot_recurse(L, K)
def dot_recurse(L, K):
if len(L) > 0:
return L[-1] * K[-1] + dot_recurse(L[:-1], K[:-1])
else:
return 0;
def dot(L, K):
if len(L)!=len(K): # return 0 before the first recursion
return 0
elif not L: # test if L is [] - previous test implies K is [] so no need to retest
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
Your code is a bit more complicated than it really needs to be. It is not possible to take the dot product of two vectors which are not the same size. There are a couple of ways to deal with receiving vectors of different sizes.
1) Lop off the remaining unused numbers from the larger vector. Below is a modified version of your function. I changed it to only require one check for if either of the vectors is empty (there is no need to check this in multiple ways), and also changed it to start from the beginning of the vectors instead of the end. Was there a particular reason you started from the end?
def dot(L, K):
if(L == [] or K == []):
return 0
else:
return L[0] + K[0] + dot(L[1:], K[1:])
While this option works, it does not give the user any indication that they made a mistake in attempting to dot product two different sized vectors.
2) Give the user an error upon receiving two different sized vectors.
def dot(L, K):
if(len(L) != len(K)):
print('Vector sizes do not match, please pass two same-sized vectors')
return 0 #not sure exactly how you are wanting to do error handling here.
elif(L == [] or K == []):
return 0
else:
return L[0] + K[0] + dot(L[1:], K[1:])
If you check out python's Operator Precedence you will see that & has lower precedence than == and and
This means you are doing the following:
if (L == ([] & K)) != []:
...
As suggested by Tuan333 you should be using and.
def dot(L, K):
if L+K == []:
return 0
elif L == [] and K != []:
return 0
elif K == [] and L != []:
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
However if you wanted to use & (which is the Binary AND, and isn't the same thing) you could just use () to force precedence
def dot(L, K):
if L+K == []:
return 0
elif (L == []) & (K != []):
return 0
elif (K == []) & (L != []):
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
If you're curious why & is likely not what you want read on:
AND takes two values, converts them to Booleans (True or False) and check that both are True
Binary AND (&) takes two values, converts them to a Number-like value, then performs an operation on their bits
Here is how I would implement this function
def dot(L, K):
if len(L) != len(K):
# Ensure the lists are the same length
raise ValueError('Can not perform dot product on two differently sized lists')
elif len(L) + len(K) == 0:
# See if we've reached the base case
return 0
else:
# Recurse doing dot product
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
print(dot([6, 2, 6], [5, 1]))

Sudoku Checker in Python

I am trying to create a sudoku checker in python:
ill_formed = [[5,3,4,6,7,8,9,1,2],
[6,7,2,1,9,5,3,4,8],
[1,9,8,3,4,2,5,6,7],
[8,5,9,7,6,1,4,2,3],
[4,2,6,8,5,3,7,9], # <---
[7,1,3,9,2,4,8,5,6],
[9,6,1,5,3,7,2,8,4],
[2,8,7,4,1,9,6,3,5],
[3,4,5,2,8,6,1,7,9]]
easy = [[2,9,0,0,0,0,0,7,0],
[3,0,6,0,0,8,4,0,0],
[8,0,0,0,4,0,0,0,2],
[0,2,0,0,3,1,0,0,7],
[0,0,0,0,8,0,0,0,0],
[1,0,0,9,5,0,0,6,0],
[7,0,0,0,9,0,0,0,1],
[0,0,1,2,0,0,3,0,6],
[0,3,0,0,0,0,0,5,9]]
I am expecting input like that- a list of 9 lists. The zeros represent number that have not been filled in by the user. They can appear multiple times in a row, column or 3x3.
def check_sudoku(grid):
if len(grid) == 9:
numsinrow = 0
for i in range(9):
if len(grid[i]) == 9:
numsinrow += 1
if numsinrow == 9:
for i in range(9):
rowoccurence = [0,0,0,0,0,0,0,0,0,0]
for j in range(9):
rowoccurence[grid[i][j]] += 1
temprow = rowoccurence[1:10]
if temprow == [1,1,1,1,1,1,1,1,1]:
return True
else:
return False
else:
return False
else:
return False
I obviously need to check that there is a 9x9 list of lists (grid), and that there are no duplicates in each row, column and 3x3 small square. In the code, I first check to see if there are a proper number of rows (There should be 9). Then I check that each row has 9 elements in it (with the ill_formed example you see that this is not the case). I then attempt to check duplicates in each row but I am having some trouble doing so. I thought that I could loop over each row and loop over each element in that row, and add 1 to a list of ints (rowoccurence). For example, if the first number is a 2, then rowoccurence[2] should be equal to 1. The zeros are in rowoccurence[0] and are not checked(I have a temporary list which should take everything except that first element- the zeros- because there could be more than 1 zero in a row and the grid could still be legit). I try to check the temp list (basically rowoccurence) against a reference list of correct values but it does not seem to be working. Could you help me check the rows for duplicates in this sudoku checker? Thank you so much in advance!
Remember, you're not searching for duplicates -- merely nonzero duplicates. Summing a set works for this. You can also check the legality of the row/column at the same time:
def sudoku_ok(line):
return (len(line) == 9 and sum(line) == sum(set(line)))
def check_sudoku(grid):
bad_rows = [row for row in grid if not sudoku_ok(row)]
grid = list(zip(*grid))
bad_cols = [col for col in grid if not sudoku_ok(col)]
squares = []
for i in range(9, step=3):
for j in range(9, step=3):
square = list(itertools.chain(row[j:j+3] for row in grid[i:i+3]))
squares.append(square)
bad_squares = [square for square in squares if not sudoku_ok(square)]
return not (bad_rows or bad_cols or bad_squares)
You return True too early, so you never make it to the test you hope to see fail:
if temprow == [1,1,1,1,1,1,1,1,1]:
return True # <-- this is the culprit
else:
return False
Misc other notes: one easy way to make sure that all elements of some vector are equal to some constant is:
all(i == const for i in vector)
Another, even easier: if vec[1:10] are all 1, then sum(vec[1:10]) must be 9. (bad idea, see comment below.)
I am only posting this because most other solutions are hardly readable though they might be really efficient. For someone who is new and just trying to learn I believe that the code below is helpful and very readable. Hope this helps anyone looking to learn how to create a sudoku checker.
def check_sudoku(grid):
for row in range(len(grid)):
for col in range(len(grid)):
# check value is an int
if grid[row][col] < 1 or type(grid[row][col]) is not type(1):
return False
# check value is within 1 through n.
# for example a 2x2 grid should not have the value 8 in it
elif grid[row][col] > len(grid):
return False
# check the rows
for row in grid:
if sorted(list(set(row))) != sorted(row):
return False
# check the cols
cols = []
for col in range(len(grid)):
for row in grid:
cols += [row[col]]
# set will get unique values, its converted to list so you can compare
# it's sorted so the comparison is done correctly.
if sorted(list(set(cols))) != sorted(cols):
return False
cols = []
# if you get past all the false checks return True
return True
Took reference from #llb 's answer, which did not check for missing values or zeros, here's my solution which would work for negative values, zeros and missing values
def line_ok(e):
if len(set(e)) != 9: return False
for i in range(len(e)):
if e[i] not in range(1,10): return False
return True
def checker(grid):
bad_rows = [False for row in grid if not line_ok(row)]
grid = list(zip(*grid))
bad_cols = [False for col in grid if not line_ok(col)]
squares = []
for i in range(0,9,3):
for j in range(0,9,3):
square = list(itertools.chain.from_iterable(row[j:j+3] for row in grid[i:i+3]))
squares.append(square)
bad_squares = [False for sq in squares if not line_ok(sq)]
return not any([bad_rows, bad_cols, bad_squares])
print(checker(sudoku_correct))
PS: Due to less reps, couldn't comment. Hope whoever needs it, finds it :)
Define a function to verify that there are no duplicates, then you can use it to check rows, columns, and 3x3 grids. You can reduce the nested blocks by returning early if some condition is not met, for example, number of rows are larger than 9. And only return true at the very end of the function if none of the checks fail.
from collections import Counter
def check_dups(l):
counts = Counter()
for cell in l:
if cell != 0: counts[cell] += 1
if cell > 9 or counts[cell] > 1: return False
return True
def check_sudoku(grid):
if len(grid) != 9: return False
if sum(len(row) == 9 for row in grid) != 9: return False
for row in grid:
if not check_dups(row): return False
return True
I think the reason your code collapse is because your indent. You should do:
for j in range(9):
rowoccurence[grid[i][j]] += 1
temprow = rowoccurence[1:10]
if temprow == [1,1,1,1,1,1,1,1,1]:
return True
else:
return False
Rather than:
for j in range(9):
rowoccurence[grid[i][j]] += 1
temprow = rowoccurence[1:10]
if temprow == [1,1,1,1,1,1,1,1,1]:
return True
else:
return False
Or use Counter:
from collections import Counter
...
if numsinrow == 9:
for i in range(9):
count = Counter(grid[i])
return False if max(count.values()) > 1 else True
valid_solution= lambda board: not any([sorted(row)!=list(range(1,10)) for row in board]) and not any([sorted(list(col))!=list(range(1,10)) for col in zip(*board)]) and not any([sorted(board[i][j:j+3]+board[i+1][j:j+3]+board[i+2][j:j+3]) !=list(range(1,10)) for i in range(0,9,3) for j in range(0,9,3)])
import numpy as np
def is_valid(row):
# checks whether a given set of values forms a valid row in sudoku
return len(list(filter(lambda val: type(val) == int and 0 < val < 10, set(row))) == 9
def check_sudoku(grid):
""" Check a sudoku board is correctly completed or not. """
# checks whether the grid has 9 rows
if len(grid) != 9:
return False
# checks whether the grid has 9 columns
for i in range(9):
if len(grid[i]) != 9:
return False
# turns grid from list to numpy array
grid = np.array(grid)
# checks whether the grid is filled with integers
if grid.dtype != np.int:
return False
for i in range(9):
# checks for repetition in rows
if not is_valid(grid[i, :]):
return False
# checks for repetition in columns
if not is_valid(grid[:, i]):
return False
# checks for repetition in squares
if not is_valid(grid[i//3*3:i//3*3+3, j%3*3:j%3*3+3]):
return False
# returns true if none of the conditions reached
return True
How about just checking each row/column with:
sorted(row) == range(1,10)
or for python 3
sorted(row) == list(range(1,10))
I imagine the running time is dominated by creating a new list (whether you do the histogram approach or the sorting approach) so the extra factor of log(n) shouldn't be noticeable
In order to check each row,column, and subsquare, I suggest having extractor methods that get the nth row, column, and subsquare from your matrix (ie don't try and put it all in one method).
So for instance:
getSubSquare(m, i):
subrow = (i // 3) * 3
subcol = (i % 3) * 3
v = [0] * 9
for j in range(9):
subrj = j // 3
subcj = j % 3
v[j] = m[subrow + subrj][subcol + subcj]
return v
getRow(m,i):
return m[i]
getCol(m,i):
return [m[j][i] for j in range(9)]
def check_sudoku(grid):
if len(grid) == 9:
numsinrow = 0
for i in range(9):
if len(grid[i]) == 9:
numsinrow += 1
if numsinrow == 9:
if checkrow(grid):
if checkcol(grid):
return True
else:
return False
else:
return False
else:
return False
else:
return False
def checkrow(grid):
for i in range(9):
rowoccurence = [0,0,0,0,0,0,0,0,0,0]
for j in range(9):
rowoccurence[grid[i][j]] += 1
temprow = rowoccurence[1:10]
for q in range(9):
if temprow[q] == 1 or temprow[q] == 0:
continue
else:
return False
return True
def checkcol(grid):
for num in range(9):
coloccurence = [0,0,0,0,0,0,0,0,0,0]
for i in range(9):
coloccurence[grid[i][num]] += 1
tempcol = coloccurence[1:10]
for q in range(9):
if tempcol[q] == 1 or tempcol[q] == 0:
continue
else:
return False
return True
Ok guys I am back with a function to check the rows which works. Thank you so much for all the extensive help. I am sort of a noob at this so I did not understand some answers but I realized that I was returning true way too early. I also realized that if there were multiple zeros in a row, then some numbers would not come up in the rowoccurence/temp list. This is why I had to check for both 1's and 0's in the rowoccurence/temp list. I have also written a similar function to check the columns. Thanks again!
If you want to check a row for duplicates, instead of
rowoccurence = [0,0,0,0,0,0,0,0,0,0]
for j in range(9):
rowoccurence[grid[i][j]] += 1
temprow = rowoccurence[1:10]
if temprow == [1,1,1,1,1,1,1,1,1]:
return True
else:
return False
count:
b = True
for i in range(9):
grid[i].count(grid[i][j]) > 1:
b = False
return b
Your approach does a bit more than just duplicate checking, it also takes care that only one digit number are present otherwise an out of bound exception will be raised
Wrote up a simple class to model a (completed) Sudoku board. Nothing tricky but a simple solution for a 9x9 board.
class SudokuBoard(object):
DIGITS = set(range(1, 10))
def __init__(self, values):
self.values = values
def row(self, n):
return self.values[n]
def rows(self):
return self.values
def cols(self):
return [self.col(i) for i in xrange(9)]
def col(self, n):
return [self.values[i][n] for i in xrange(len(self.values))]
def groups(self):
return [self.group(i) for i in xrange(9)]
def group(self, n):
start_r = (n / 3) * 3
start_c = n * 3 % 9
values = []
for row in xrange(start_r, start_r + 3):
for col in xrange(start_c, start_c + 3):
values.append(self.values[row][col])
return values
def is_correct(self):
for row in self.rows():
if self.DIGITS - set(row):
return False
for col in self.cols():
if self.DIGITS - set(col):
return False
for group in self.groups():
if self.DIGITS - set(group):
return False
return True
I wrote the code on https://github.com/loghmanb/daily-coding-problem
from collections import defaultdict
def solution_valid(board)
#check row and column is distict no or not?!
rows = defaultdict(int)
columns = defaultdict(int)
squares = defaultdict(int)
for i in range(9):
rows.clear()
columns.clear()
squares.clear()
for j in range(9):
if board[i][j] is not None:
columns[board[i][j]] += 1
if columns[board[i][j]]>1:
return False
if board[j][i] is not None:
rows[board[j][i]] += 1
if rows[board[j][i]]>1:
return False
new_j = (i*3 + j%3)%9
new_i = (i//3)*3 + j//3
if squares[board[new_i][new_j]] is not None:
squares[board[new_i][new_j]] += 1
if squares[board[new_i][new_j]]>1:
return False
return True
The question is old, but I leave a new contribution for others who come here, like me.
Correct me if I'm wrong, but I think the solution is quite simple. No need to check for duplicates in row, column and grid. Just check the row. Because if there are duplicates in the column or in the grid, there will also be duplicates in the row.
So I think it's enough to check for 0 and duplicates on the row:
from collections import Counter
solved = True
for row in board:
if max(Counter(row).values()) > 1: solved = False
elif 0 in row: solved = False

Categories

Resources