Balanced Parenthesis challenge: Checking for string that contains no parenthesis - python

I did an implementation on checking if whether a string has balanced parentheses or not using a STACK only. But I checked for balanced parentheses when the string has words. For example:
>>> is_paren_balanced("[{whoa (this is rough [how do I do this!])}]")
True
I was successful in doing that. However, I am not trying to check for a case if the string has NO parenthesis. And then i got this result:
>>> is_paren_balanced("Hi i love food.")
no parenthesis
True
>>> is_paren_balanced("[{whoa (this is rough [how do I do this!])}]")
no parenthesis
False
For the first result, I don't want the boolean result as thats kind of vague. I'm trying to show the user that the string has no parenthesis so it is neither True or False. I just want the print statement shown saying "no parentheses here" or whatever. For the second result, obviously just the boolean result and it shouldve returned True.
Any suggestions? I'm stumped.
Here is the code I'm practicing with:
from stack import Stack
def is_match(p1, p2):
if p1 == "(" and p2 == ")":
return True
elif p1 == "{" and p2 == "}":
return True
elif p1 == "[" and p2 == "]":
return True
else:
return False
def is_paren_balanced(paren_str):
s = Stack() #initialize a stack object
is_balanced = True #boolean flag: whether the str has balanced parenthesis or not
# then set to false if otherwise
index = 0 # keep track of where we are in the string
paren_str = paren_str.replace(" ", "") #accounts for possible spaces in the input
while index < len(paren_str) and is_balanced:
paren = paren_str[index]
if paren in "({[":
s.push(paren)
elif paren in ")}]":
if s.is_empty():
is_balanced = False
else:
top = s.pop()
if not is_match(top, paren):
is_balanced = False
else:
if paren not in "({[]})":
print("no parenthesis")
break
index += 1
if s.is_empty() and is_balanced:
return True
else:
return False
Sorry if it doesn't seem pythonic. I was just mostly exploring with this problem and will edit and improve later on.

You can use either regex or list comprehension to get the total amount of parenthesis first:
import re
def all_parenthesis(msg):
left = re.findall(r"[\[{(]",msg)
right = re.findall(r"[\]|})]",msg)
if not left and not right:
return "No parenthesis"
#or
def check_balance(msg):
d = {"[":"]",
"{":"}",
"(":")"}
left = [char for char in msg if char in d]
right = [char for char in reversed(msg) if char in d.values()]
#if not left not right...
But if you already constructed a list of parenthesis on both sides, why don't go ahead and compare them instead? Could be something like this:
def check_balance(msg):
d = {"[":"]",
"{":"}",
"(":")"}
left = [char for char in msg if char in d]
right = [char for char in reversed(msg) if char in d.values()]
if not left and not right:
return "No parenthesis"
elif len(left) != len(right):
return False
for a, b in zip(left,right):
if d.get(a) != b:
return False
return True

Related

Can someone tell me why after returning a boolean of False my code goes backwards and chooses True also

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.
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.
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)))
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, then n 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 that n != len(word), and as n starts with 0, that if condition would have been false if word was the empty string.
When you pass in the first if 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 of word[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)
)

Given a string, return true if the first instance of “x” in the string is immediately followed by another “x”

Note :
capital X's do not count as an occurrence of "x".
if there are no "x"'s then return false
The following code is my solution, however i don't get the correct answer.
def triple_x(s):
for i in (s):
if i == 'x' and i+1 =='x':
return True
else:
return False
TEST CASES:
tripleX("abraxxxas") → true
tripleX("xoxotrololololololoxxx") → false
tripleX("softX kitty, warm kitty, xxxxx") → true
tripleX("softx kitty, warm kitty, xxxxx") → false
I would be appreciate if someone can help me. Thank you.
All you had to do is just do something similar to this
def myx(word):
if 'xx' in word : return True
return False
print(myx('xoxotrololololololoxxx')) # this will print out true s
Much simpler and cleaner. hoped this resolve your question
The parentheses around s are superfluous. i runs over s, so it will take the value of the characters in s, one at a time.
As a result, i+1 does not give you the next character in s, instead it tries to add 1 to that character of s, which doesn't make sense.
You can use your solution, if you have i range over the indexes of characters in s. Also, your current solutions doesn't take into account a situation like s = "oxoxxx" where the first x doesn't meet your criteria, but the second one does (in which case I assume you need the answer to be False)
This stays close to your solution, but works:
def triple_x(s):
for i in range(len(s)):
if s[i] == 'x':
if i+1 < len(s) and s[i+1] =='x':
return True
else:
return False
A shorter way of writing the same:
def triple_x(s):
for i in range(len(s)):
if s[i] == 'x':
return i+1 < len(s) and s[i+1] =='x':
As the comparison returns a bool value.
Here's a solution that's close to optimal:
def triple_x(s):
i = s.find('x')
return i+1 != len(s) and s[i+1] == 'x'
I would use re.search here for a regex approach:
inp_valid = "blah blah xx other text here"
if re.search(r'^[^x]*xx', inp_valid):
print "VALID"
else:
print "INVALID"
inp_invalid = "blah blah xtra text here"
if re.search(r'^[^x]*xx', inp_invalid):
print "VALID"
else:
print "INVALID"
This prints:
VALID
INVALID

String comparison and sorting function

I'm designing a guess word game and I need some help with one of the functions.
The function receives 2 inputs and returns true or false.
The input my_word contains letters that were guessed and match to a certain word.
The input other_word is some word to compare with my_input.
examples:
>>> match_with_gaps("te_ t", "tact")
False
>>> match_with_gaps("a_ _ le", "apple")
True
>>> match_with_gaps("_ pple", "apple")
True
>>> match_with_gaps("a_ ple", "apple")
False
My problem is applying it to return a False as in the last example and I'm not sure how to do it. This is what I have done so far. It works but not for a case when a one guessed letter in my_word appears 2 time in other_word. In this case I'm returning true but it should be False.
The inputs must be the exactly in the format as in the example (space after underscore).
def match_with_gaps(my_word, other_word):
myWord = []
otherWord = []
myWord_noUnderLine = []
for x in my_word:
if x != " ": # remove spaces
myWord.append(x)
for x in myWord:
if x != "_": # remove underscore
myWord_noUnderLine.append(x)
for y in other_word:
otherWord.append(y)
match = ( [i for i, j in zip(myWord, otherWord) if i == j] ) # zip together letter by letter to a set
if len(match) == len(myWord_noUnderLine): # compare length with word with no underscore
return True
else:
return False
my_word = "a_ ple"
other_word = "apple"
print(match_with_gaps(my_word, other_word))
You could create a "no space" version and a "no space, no underscore" version of your string and then compare each character to see if non underscore characters matched or if characters corresponding to an underscore have already been used. For example:
def match_with_gaps(match, guess):
nospace = match.replace(' ', '')
used = nospace.replace('_', '')
for a, b in zip(nospace, guess):
if (a != '_' and a != b) or (a == '_' and b in used):
return False
return True
print(match_with_gaps("te_ t", "tact"))
# False
print(match_with_gaps("a_ _ le", "apple"))
# True
print(match_with_gaps("_ pple", "apple"))
# True
print(match_with_gaps("a_ ple", "apple"))
# False
This line here:
if len(match) == len(myWord_noUnderLine)
Will not give you what you want right now. In the "a_ ple" example, both the space and the "_" are removed, so your myWord_noUnderLine variable will be "aple", so checking for a length match will surely fail between "aple" and "apple"

IndexError when checking if input is palindrome using while loop

I'd like to know how do I check if an input is a palindrome with a while loop, using Python.
Thanks:
i tried this
i = 0
n = len(msg_list)
while i < n:
palindrome = msg_list[i]
if palindrome == msg_list[-1]:
print("Palindrome? True")
msg_list.pop(-1)
else:
print("Palindrome? False")
i=i+1
but at the end I receive an error message that the list index is out of range
You don't need to iterate till the end, but only till the middle character. And compare every character to the character at the same index when counted in reverse:
s = "abcca"
length = len(s)
i = 0
while i < length / 2 + 1:
if s[i] != s[-i - 1]:
print "Not Palindrome"
break
i += 1
else:
print "Palidrome"
else part of the while loop is executed, when the loop completes its iteration without any break.
Alternatively, if you can use anything else than a while loop, then this task is just of single line in Python:
if s == s[::-1]:
print "Palindrome"
Oh, it became two lines.
With a while loop
import string
palin = 'a man, a plan, a canal, panama'
def testPalindrome(in_val):
in_val = in_val.lower()
left, right = 0, len(in_val) - 1
while left < right:
char_left, char_right = '#', '#'
while char_left not in string.lowercase:
char_left = in_val[left]
left += 1
while char_right not in string.lowercase:
char_right = in_val[right]
right -= 1
if char_left != char_right:
return False
return True
print testPalindrome(palin)
Without
>>> palindrome = 'a man, a plan, a canal, panama'
>>> palindrome = palindrome.replace(',', '').replace(' ', '')
>>> palindrome
'amanaplanacanalpanama'
>>> d[::-1] == d
True
A short solution using reversed:
for c, cr in s, reversed(s):
if c != cr:
print("Palindrome? False")
break
else:
print("Palindrome? True")
Another way using a while loop. Once two characters don't match, the while loop stops, so it's quite efficient but of course not the best way to do it in Python.
def palindrome(word):
chars_fw = list(word)
chars_bw = list(reversed(word))
chars_num = len(word)
is_palindrome = True
while chars_num:
if chars_fw[chars_num-1] != chars_bw[chars_num-1]:
is_palindrome = False
break
chars_num -= 1
return is_palindrome
Figured I would add another alternative for people still viewing this question. It uses a while loop, and is reasonably concise (although, I still prefer the if word = word[::-1] approach.
def is_palindrome(word):
word = list(word.replace(' ', '')) # remove spaces and convert to list
# Check input
if len(word) == 1:
return True
elif len(word) == 0:
return False
# is it a palindrome....
while word[0] == word[-1]:
word.pop(0)
word.pop(-1)
if len(word) <= 1:
return True
return False
word = "quiniuq"
pairs = zip(word,reversed(word))
a,b = next(pairs)
try:
while a == b:
a,b = next(pairs)
return False # we got here before exhausting pairs
except StopIteration:
return True # a == b was true for every pair
The use of a while loop here is contrived, but it will consume the whole list and perform the test.
If a while loop wasn't a requirement, one would do: all(a == b for a,b in zip(word,reversed(word)))

Running code isn't providing any output

I have a program that, simplified, looks like this:
def listAssign(lst,index,item):
"""Assigns item item to list lst at index index, returns modified list."""
lst[index] = item
return lst
def listInsert(lst,index,item):
"""Inserts item item to list lst at index index, returns modified list."""
lst.insert(index.item)
return lst
# ...
def listSurgery(lst,indices,f,*extraArgs):
"""Performs operation f on list lst at depth at indices indices, returns modified list."""
parent = lst
for index in indices[:-1]:
parent = parent[index]
parent = f(parent,indices[-1],*extraArgs)
return listSurgery(lst,indices[:-1],listAssign,parent)
# ...
def parseStringToList(s):
"""Takes in a user-input string, and converts it into a list to be passed into parseListToExpr."""
for c in s[:]: # Removes extra spaces from beginning of string
if c == ' ':
s = s[1:]
else:
break
for c in s[::-1]: # Removes spaces from end of string
if c == ' ':
s = s[:-1]
else:
break
l = [] # List to build from string; built by serially appending stuff as it comes up
b = True # Bool for whether the parser is experiencing spaces (supposed to be True if last character processed was a space)
t = False # Bool for whether the parser is experiencing a string of non-alphanumeric characters (supposed to be True if last character was a non-alphanumeric character)
lvl = 0 # Keeps track of depth at which operations are supposed to be occurring
for c in s:
if c == ' ': # If the character is a space, do nothing, but make sure that it's documented that the last character processed was a space
b = True
elif c == '(' or c == '[': # If the character is an opening parenthesis, add a new level of depth to the list, by appending another list to the lowest level and incrementing lvl
l = listSurgery(l,[-1]*(lvl+1),listInsert,[])
lvl += 1
if c == '[': # ] (left here for overzealous parsers) If the bracket is square, also append a comma as the first element of the appended list
l = listSurgery(l,[-1]*(lvl+1),listInsert,',')
elif c == ')' or c == ']': # If it's a closing parenthesis, make it stop paying attention to the list it's working on
lvl -= 1
elif c == ',': # If it's a comma, then append it to the list as a separate element and start a new string to append characters to
l = listSurgery(l,[-1]*(lvl+1),lambda x,y,z:listAssign(x,y,x[y]+z),[',',''])
elif not c.alnum(): # If it's non-alphanumeric and not any of the above, then append it to string that it's working on if it's a non-alphanumeric string
if not t: # If the string that it's working on isn't non-alphanumeric, then finish working on that string and append a new string to work on
l = listSurgery(l,[-1]*(lvl+1),listInsert,'')
l = listSurgery(l,[-1]*(lvl+1),lambda x,y,z:listAssign(x,y,x[y]+z),c)
t = True
else: # If the character is alphanumeric, append it to the string it's working on
assert c.isalnum()
if b or t: # If the string it's working on isn't alphanumeric or doesn't exist, append a new string
l = listSurgery(l,[-1]*(lvl+1),listInsert,'')
b, t = False, False
l = listSurgery(l,[-1]*(lvl+1),lambda x,y,z:listAssign(x,y,x[y]+z),c)
return l
# ...
cmds = {
'help':"List the available functions.",
'quit':"Quit this application.",
'exit':"Exit this application (exactly the same thing)."
}
print "MAT (Michael's Analysis Tool), version 0.0.0"
op = '' # Declare string to use for input
while op != 'exit' and op != 'quit': # Keep a REPL unless the user types "exit" or "quit", in which case exit
op = raw_input("> ")
if op == 'help':
print "The commands available in addition to free evaluation are:"
for item in cmds:
print ' ', item + ":", cmds[item]
elif op == 'quit' or 'exit':
pass
else:
print str(parseStringToList(op))
When I use help, quit, or exit as a command, it comes out fine. But when I give it any other kind of input like 1 + 1 = 2 (which should elicit ['1','+','1','=','2']) or This is a sentence. (which should elicit ['This','is','a','sentence','.'], it doesn't print anything, just asks for more input. (That is, it's functionally equivalent to the last line of this program getting replaced with continue.) And I don't understand why. parseStringToList is defined in a very straightforward manner. It should at least return [], the original value of the variable it returns. But instead it doesn't print anything. Why? (I'll try more thorough debugging tomorrow, but so far it's eluded my efforts.)
You need to change this:
elif op == 'quit' or 'exit':
to this
elif op == 'quit' or op == 'exit':

Categories