Can someone tell me why after returning a boolean of False
my code goes backwards and chooses True
also even though the False
was the right output I see this happening in the debugger, I only found this happening with this specific example. So the function of my code is to take a pattern from user and see if it matches the word given by the user, the format of a pattern is "?ead"
which would match with the word lead, the question mark is just a placeholder for any character so it can be anything but every other character has to be the same.
n = 0
def match(pattern, word):
global n
if n != len(word): # setting a base case for the recurrsion so it stops at the end of the word
if pattern == "" and word == "":
pass
elif pattern == '' or word == '':
pass
elif len(word) != len(pattern):
return False
if word[n:n 1] == pattern[n:n 1] or pattern[n:n 1] == '?': # goes through each character and compares them for each
n = n 1
match(pattern, word)
print("same")
return True # This is where the code goes back to and returns true after already returning false down below in the else statement.
else:
print("not same")
return False
match("?ut","cat")
The pattern my code fails for "?ut"
and the word is "cat"
, the code sees that the first character is fine since "?" is just a placeholder and it also sees that the second term does not match so it should evaluate to false which it does but then immediately exits and evaluates to true and all this needs to be done with recursion and no loops.
CodePudding user response:
You are trying to do recursion here. It can be done like this:
def match(pattern, word):
#Little debug for you to see what is happening
print (pattern, word)
if len(pattern) != len(word):
return False
if not word and not pattern:
# last round with empty strings, all same this far
return True
if pattern[0] != word[0] and pattern[0] != "?":
return False
# reduce both strings and go to next round
return match(pattern[1:], word[1:])
So you reduce both pattern and word and if you find that they don't match return false. If you get to the end, return True.
CodePudding user response:
You do not return the result of match but return True. You should simplify your cases.
if word[n:n 1] == pattern[n:n 1] or pattern[n:n 1] == '?': n = n 1 match(pattern, word) # this can return True OR False print("same") return True # You always return True # return match(pattern, word) instead
There is no need for a global "counter" - if you recurse, shorten your pattern/word until nothing is left:
def match(pattern, word):
if len(pattern) != len(word):
return False
# done all I can do
if pattern == "" and word == "":
return True
# no comparison if pattern is ?
if pattern[0] == "?":
# recurse with 1 shorter pattern/word
return match(pattern[1:], word[1:])
# same letters
elif pattern[0] == word[0]:
# recurse with 1 shorter pattern/word
return match(pattern[1:], word[1:])
# different
return False
for pat,wrd in [("?ut","cat"), ("ok","ok"), ("?k","ok"),
("o?","ok"), ("",""), ("tooShort","veryLongWord")]:
print(pat,wrd, "=>", "same" if match(pat,wrd) else "different")
Output:
?ut cat => different
ok ok => same
?k ok => same
o? ok => same
=> same
tooShort veryLongWord => different
Or use the "short" version that does not recurse:
def match(pattern, word):
return len(pattern)==len(word) and all(
(p==w or p == "?" for p,w in zip(pattern, word)))
CodePudding user response:
You should return the result you get back from recursion. Currently you ignore it.
There are some other issues:
Don't use global variables. If you make another call to
match
, thenn
will still be the value it had after the first call, and so you'll get an unreliable result from the second call. Instead make it an argument to your function. You can give it a default value.The condition
if pattern == "" and word == "":
can never be true, since you already had assured thatn != len(word)
, and asn
starts with 0, thatif
condition would have been false ifword
was the empty string.When you
pass
in the firstif
blocks, the other code below is still executed, and so you'd make an invalid index reference in the string.Adding another condition where you delimit strings with single quotes instead of double quotes is not changing anything. You still compare the same strings.
It is overkill to compare slices of one character. Just retrieve the single character you want to compare. So
word[n]
instead ofword[n:n 1]
Don't print the result inside the function. Print at the caller's side.
Correction:
def match(pattern, word, n=0):
if len(word) != len(pattern):
return False
if n >= len(word):
return True
if word[n] != pattern[n] and pattern[n] != '?':
return False
return match(pattern, word, n 1)
print(match("?ut","cat"))
Not your question, but this kind of recursion is a case of tail recursion, and so it could be written with simple iteration:
def match(pattern, word):
if len(word) != len(pattern):
return False
for i, pat in enumerate(pattern):
if word[i] != pat and pat != '?':
return False
return True
When you are confortable with comprehension syntax you can write that also like this:
def match(pattern, word):
return len(word) == len(pattern) and all(
pat in ('?', ch) for ch, pat in zip(word, pattern)
)