pop() empty deque() in logic - python

I want to be able to validate parenthesis so they enclose and ignore any type of characters. As long as there is the valid use of enclosure of strings with parenthesis then True else `False.
I am still new to python so I'm not sure how to properly create an if statement for this certain condition. I am trying to create an fi statement such that when I .pop() an empty deque() I will be able to return False instead of receiving the error message:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop from an empty deque
Perhaps there is another better method around solving this problem. If so I would be glad to see how someone else would solve it
For example:
a = 'sdf(sadf(sdf)sdf)sdfsd0sdf)sdf(sdf0)' # false
b = 'dsf))))(((((dsfsdf' # false
c = '()()()()' # true
d = '((((asd(asd)asd)()()asd))' # true
my code:
# any letter is ignored
# jsut make sure that the parenthesis are equal
from collections import *
def str_valid(stringy):
param_stack = deque()
for n in stringy:
if n ==')':
param_stack.pop()
if n == '(':
param_stack.append('(')
if param_stack == []:
return True
else:
return False
a = 'sdf(sadf(sdf)sdf)sdfsd0sdf)sdf(sdf0)' # false
b = 'dsf))))(((((dsfsdf' # false
c = '()()()()' # true
d = '((((asd(asd)asd)()()asd))' # true
print str_valid(a)
print str_valid(b)
print str_valid(c)
print str_valid(d)

If you just want an if statement to check if the deque is empty before pop(), you can use
if n ==')':
if param_stack:
param_stack.pop()
else:
return false
...
if param_stack will implicitly convert it to a boolean which return true if it contains some elements and false otherwise.

A few things to note: first, the only methods of deque you're using are append() and pop. So it's more natural to use an ordinary Python list. A deque isn't more efficient than a list unless you need to put things on, or take things off, "the left end".
Second, you already know how to test for an empty deque! You did that here:
if param_stack == []:
Now that's a little odd, because you're comparing a deque to a list, but it works. With a little more experience, you'll write that as:
if len(param_stack) == 0:
and with more experience still, you may use:
if not param_stack:
(an empty container generally behaves like False in truth-y contexts).
But however you write it, rather than introduce try/except blocks, it's easier and clearer to do something like:
if n ==')':
if param_stack: # i.e., if it's not empty
param_stack.pop()
else: # it's empty
return False
Clear?

If you just want to pop() an empty deque without problems:
from collections import deque
d = deque()
try:
d.pop()
except IndexError:
pass # do whatever you want in the case that there is nothing there
return False # is this what you want?
else:
pass # do whatever you want in the case that there is something there
Just a warning in case you don't know: keep the amount of code inside any of try/except/else/finally as short and focused as possible. It's easy to end up with errors popping up inside error handlers and leading to surprises.
If that's not what you need, please clarify what in your code is not working.

Simply catch the error and return False:
for n in stringy:
if n ==')':
try:
param_stack.pop()
except IndexError:
return False

Use try, except to catch the IndexError exception and then return False
try:
param_stack.pop()
except IndexError:
# catch your IndexError exception and do what you want
return False

As other people already mentioned you don't really need a queue, a simple counter is enough:
def str_valid(txt):
ctr = 0
for n in txt:
if n == '(':
ctr = ctr + 1
if n == ')':
ctr = ctr - 1
if ctr < 0:
return False
return ctr == 0
Or shorter:
def str_valid(txt):
ctr = 0
for n in txt:
ctr = ctr + (n == '(') - (n == ')')
if ctr < 0:
return False
return ctr == 0
Or a "hacky" one-liner :)
def str_valid(txt):
return not reduce(lambda t, c: t if t < 0 else t + (c == '(') - (c == ')'), txt, 0)

Related

How to write this iterative function to be recursive?

I need to write this iterative function to do the same thing but it must be recursive.
def task1(string: str):
for i in range(len(string)):
if string[i] != string[len(string) - i - 1]:
return False
return True
This is what i tried but it does not work.
def task1_recursion(string: str):
print(string)
if len(string) > 1:
if string[0] == task1_recursion(string[1::1]):
return True
else:
return False
else:
return string
My code seems to one the last recursion return string "" and that makes it to return False.
Just check the tip and the tail, continue with the string without them:
def task1_recursion(string: str):
# recursion base condition (exit condition)
if len(string) <= 1:
return True
# unpack values
first, *_, last = string
# check if they are different
if first != last:
return False
# if not continue checking the remaining string
return task1_recursion(string[1:-1])
If I understand correctly you want to check if a string is symmetric with the code in task1. My solution is below:
def fct(s: str, i: int):
if len(s) <= 1 or i == len(s):
return True
return s[i] == s[len(s) - 1 - i] and fct(s, i + 1)
I tested and fct produces the same result as task1. It needs an additional parameter for the index though. But you can wrap it inside another function if you want the parameter to include only the input string. i is always set to 0 when you call the function, e.g. fct("ABCCBA", 0).

Python 3: String validation (password)

Individually, these statements work (I've made individual helper functions) and I've compiled them onto one function. How am I able to get them to work together? Additionally, how would I make this program run without module 're'? It works but I got it off someone else on this site. These are what I need in this program:
Has to have a number
Characters in the beginning and end of the string have to be letters
Must be between 10 and 20 characters
There can't be 3 characters in a row
Previous password can't be used again
Here is my code:
import re
def password_validator (pw_v, prev_p): #pw_v = string that is to be validated; prev_p = previously used strings in a list
prev_P = [s]
# do I use 'while True' instead of returning True statements every time?
if 10 <= len(s) <=20:
return True
elif s[0] and s[-1].isalpha():
return True
elif not re.search('(.)\\1{2}', s): # How else can I write this without using 're'?
return True
elif any(digit.isdigit() for digit in s):
return True
else:
return False
Your code checks if the input satisfies only one of the conditions.
Note that when you return, the function returns and ignores the rest of the code. Considering this fact, you can use either:
(1) Nested ifs
if 10 <= len(s) <= 20:
if s[0] and s[-1].isalpha():
# the rest of the conditions
return True # all of the conditions were met
return False # one of the conditions wasn’t met
(2) Return false when one the first condition isn't met (which actually uses De Morgan's laws).
if not 10 <= len(s) <= 20:
return False
if not s[0] and s[-1].isalpha():
return False
# the rest of the conditions
Regarding the regex use, in my opinion it's elegant in this case; but you can always switch to a loop that iterates over the input's characters, combined with a counter of repeated characters (which isn't as elegant):
def three_identical_characters(input):
counter = 0
for i in range(1, len(input)):
counter += (1 if (input[i] == input[i-1]) else 0)
if counter == 2:
return True
return False
Store each of the conditions results in a variable, e.g. has_correct_length and has_digit.
Combine them:
has_correct_length = (10 <= len(s) <=20)
has_digit = any(digit.isdigit() for digit in s)
fulfills_restrictions = has_correct_length and has_digit
This way your code is much easier to read and documents itself.
You don't test if the condition is met, you test if the condition is not met:
import re
def password_validator (pw_v, prev_p): #pw_v = string that is to be validated; prev_p = previously used strings in a list
prev_P = [s]
# do I use 'while True' instead of returning True statements every time?
if not 10 <= len(s) <=20:
return False
elif not (s[0] and s[-1].isalpha()):
return False
elif re.search('(.)\\1{2}', s): # How else can I write this without using 're'?
return False
elif not any(digit.isdigit() for digit in s):
return False
else:
return True

Returning True if the number of opening and closing parentheses are the same

I'm trying to create a function that will return true if the number of opening and closing parentheses in a string are equal. If they're not, I need it to return false. Currently this is not working for all strings. For example, paren_parity('p)(()ld))()(eog((h)k(j(m()(nc)fab)i)',) returns true as it should but paren_parity('d)p))mk)bc))j((eif(()ln)o)h((ag',) is returning True even though the number of open and closed parentheses are not the same.
def paren_parity(z):
stack = []
pushChars, popChars = "<({[", ">)}]"
for c in z :
if c in pushChars :
stack.append(c)
elif c in popChars :
if not len(stack) :
return False
else :
stackTop = stack.pop()
balancingBracket = pushChars[popChars.index(c)]
if stackTop != balancingBracket:
return False
else :
return True
return not len(stack)
You've got a couple choices. The first is really easy, just count the number of opening parens and closing and check for equality:
def paren_parity(z):
return z.count('(') == z.count(')')
But, this will pass strings like '))))((((' which you might not want. Otherwise, you can keep a count of the number of opened parens as you walk over the string. If the count ever goes negative, then return False:
def paren_parity(z):
open_count = 0
for c in z:
if c == '(':
open_count += 1
if c == ')':
open_count -= 1
if open_count < 0:
return False
return open_count == 0
Of course, this still doesn't actually work for parsing programming language text because it'll fail for things like a = 5 * ('yeah!)') (since I have a parenthesis embedded in a string). However, I'm going to assume that isn't an issue for your current problem ;-).
This is your problem:
else :
return True
If you encounter something that isn't a parenthesis, you always return True. So d( will return True as soon as you hit the d.
You can fix it by just removing the those lines.
This is easily resolved with a tail recursive function, including determining if there is a 'mismatch'.
def paren_parity(z, opening=0):
if len(z) == 0:
return opening == 0
head, *tail = z
if head == "(":
opening = opening + 1
elif head == ")":
if opening == 0:
return False
opening = opening - 1
return paren_parity(tail, opening)
opening acts as the stack you're pushing and popping from. Since you don't care as to the value, just whether it's a push or pop, holding an integer is enough.

Function that checks if brackets are balanced in python

I have written the following code to check if some input to the function contains balanced brackets:
def balanced_brackets(text):
brackets = [ ('(',')'), ('[',']'), ('{','}'),('<','>')]
s = 0
e = 1
st = Stack()
for i in text:
for pair in brackets:
if i == pair[s]:
st.push(i)
elif i == pair[e] and not st.isEmpty() and st.pop() != pair[s]:
return False
if st.isEmpty():
return True
else:
return False
This code is working for input such as '()(())()' but it failed when I tried it for 'zn()((b)())q())()l()d(r)'. Can anyone help me identify what the problem is? Thanks.
Your problem is with the and not st.isEmpty()==0. When it gets to the unbalanced ')', all the previous ones have balanced out, so st is empty.
If you have a i == pair[e], and your stack is empty, you want to return False.
You also want to return False if you pop and it isn't pair[e]. But you don't want to pop if the stack is empty.
What you have now, in condition 1, just keeps going. You need to change around the condition there so that it accounts for both, or have two elifs. The former can be achieved with some nesting ands and ors.
By the way; unless you want to do something fancy with it, there's no real need to implement a stack. You can just use a list instead, with l.pop, len(l), and l.append.
This works.It needs a stack module to import. It will keep track of matched pairs.
def multi_bracket_validation(input):
""" test for matching brackets and return bool """
if type(input) is str:
open_b = '({]'
closed_b = ')}]'
compare = Stack()
for brac in input:
if brac in open_b:
compare.push(brac)
elif brac in closed_b:
if compare.top is None:
return False
if closed_b.index(brac) != open_b.index(compare.pop().val):
return False
return compare.top is None
return False

How can I return false if more than one number while ignoring "0"'s?

This is a function in a greater a program that solves a sudoku puzzle. At this point, I would like the function to return false if there is more then 1 occurrence of a number unless the number is zero. What do am I missing to achieve this?
L is a list of numbers
l =[1,0,0,2,3,0,0,8,0]
def alldifferent1D(l):
for i in range(len(l)):
if l.count(l[i])>1 and l[i] != 0: #does this do it?
return False
return True
Assuming the list is length 9, you can ignore the inefficiency of using count here (Using a helper datastructure - Counter etc probably takes longer than running .count() a few times). You can write the expression to say they are all different more naturally as:
def alldifferent1D(L):
return all(L.count(x) <= 1 for x in L if x != 0)
This also saves calling count() for all the 0's
>>> from collections import counter
>>> def all_different(xs):
... return len(set(Counter(filter(None, xs)).values()) - set([1])) == 0
Tests:
>>> all_different([])
True
>>> all_different([0,0,0])
True
>>> all_different([0,0,1,2,3])
True
>>> all_different([1])
True
>>> all_different([1,2])
True
>>> all_different([0,2,0,1,2,3])
False
>>> all_different([2,2])
False
>>> all_different([1,2,3,2,2,3])
False
So we can break this down into two problems:
Getting rid of the zeros, since we don't care about them.
Checking if there are any duplicate numbers.
Striping the zeros is easy enough:
filter(lambda a: a != 0, x)
And we can check for differences in a set (which has only one of each element) and a list
if len(x) == len(set(x)):
return True
return False
Making these into functions we have:
def remove_zeros(x):
return filter(lambda a: a != 0, x)
def duplicates(x):
if len(x) == len(set(x)):
return True
return False
def alldifferent1D(x):
return duplicates(remove_zeros(x))
One way to avoid searching for every entry in every position is to:
flags = (len(l)+1)*[False];
for cell in l:
if cell>0:
if flags[cell]:
return False
flags[cell] = True
return True
The flags list has a True at index k if the value k has been seen before in the list.
I'm sure you could speed this up with list comprehension and an all() or any() test, but this worked well enough for me.
PS: The first intro didn't survive my edit, but this is from a Sudoku solver I wrote years ago. (Python 2.4 or 2.5 iirc)

Categories