Get RPN tree size - python

I've implemented the following 'tree sizer' but it fails under certain conditions, the example below returns size 2 when it should return size 4, can anyone help me out. I've written this several times, to no avail, it keeps failing.
def getRPNdepth(expression):
treesize=0
maxtreesize=treesize
mintreesize=treesize
tmpexp=expression
tmpfmla = [1 if n[0] == 'x' else n for n in tmpexp]
print(tmpfmla)
try:
stack = []
for val in tmpfmla:
if val in ['-', '+', '*', '/']:
op1 = stack.pop()
op2 = stack.pop()
if val == '-': result = op2 - op1
if val == '+': result = op2 + op1
if val == '*': result = op2 * op1
if val == '/':
if op1 == 0:
result = 1
else:
result = op2 / op1
stack.append(result)
treesize=treesize+1
else:
stack.append(float(val))
treesize = treesize - 1
if treesize>maxtreesize:
maxtreesize=treesize
if treesize<mintreesize:
mintreesize=treesize
return abs(mintreesize)
except:
print('error validate rpn>' + str(expression))
return 0
xxxx = ['x6', 'x7', '+', 'x7', '+', 'x7', '+', 'x7', '+']
print(getRPNdepth(xxxx))
a couple of examples :
['1','1' ,'+','1','1' ,'+' ,'+']
['1','1','1' ,'+' ,'+']
both give the result of 3, which is correct, but.
['1','1' ,'+','1','1' ,'+' ,'+']
returns 3 when it should be 4
All in all, I need to know the depth of the RPN from its string representation.

Calculating the tree depth is similar to evaluating the expression, but the operators calculate resulting depths instead of resulting values:
def getRPNdepth(expression):
stack = []
for val in expression:
if val in ['-', '+', '*', '/']:
stack.append(max(stack.pop(),stack.pop())+1)
else:
stack.append(1)
return stack.pop()

Well, just did a little of 'cheating' and used my rpn to infix converter to achieve the same goal, I post it here if anyone need it.
def getRPNdepth(expression):
tmpexp = expression
tmpfmla = [1 if n[0] == 'x' else n for n in tmpexp]
stack = []
for val in tmpfmla:
if val!=' ':
if val in ['-', '+', '*', '/']:
op1 = stack.pop()
op2 = stack.pop()
stack.append('(' + str(op1) + str(val) + str(op2) + ')')
else:
stack.append(str(val))
openparentesiscount=0
maxopenparentesiscount = 0
onlyparentesis=''
for c in stack[0]:
if c in ['(', ')']:
onlyparentesis=onlyparentesis+c
if c=='(':
openparentesiscount=openparentesiscount+1
else:
openparentesiscount = openparentesiscount - 1
if openparentesiscount>maxopenparentesiscount:
maxopenparentesiscount=openparentesiscount
return maxopenparentesiscount
Thanks all !

Related

Infix evaluation in Python

I am trying to convert the code here http://www.geeksforgeeks.org/expression-evaluation/ to python. However, I am running into some trouble and can't figure out.
class evaluateString:
def evalString(self,expression):
valueStack = []
opStack = []
i=0
while(i<len(expression)):
if(expression[i] == ' '):
continue
if(expression[i]>='0' and expression[i] <= '9'):
charNumber = [] #for storing number
while(i<len(expression) and expression[i]>='0' and expression[i] <= '9'):
charNumber.append(expression[i])
i+=1
valueStack.append(int(''.join(charNumber)))
elif (expression[i]=='('):
opStack.append(expression[i])
elif (expression[i]==')'):
while(opStack[-1]!='('):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.pop()
elif(expression[i]=='+'or expression[i]=='-'or expression[i]=='*'or expression[i]=='/'):
while( (len(opStack)!=0) and ( self.opPrecedence(expression[i],opStack[-1]) ) ):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.append(expression[i])
i = i + 1
while(len(opStack)!=0):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
return valueStack.pop()
def applyOperation(self,op,a,b):
if op=='+':
return a+b
elif op=='-':
return a-b
elif op=='*':
return a*b
elif op=='/':
return a/b
else:
return 0
def opPrecedence(self,op1,op2):
if (op2 == '(' or op2 == ')'):
return False
if ((op1 == '*' or op1 == '/') and (op2 == '+' or op2 == '-')):
return False
else:
return True
a = evaluateString()
print(a.evalString("(5+7)"))
I am able to get the right numbers in the valueStack. However, there seems to be problem in the last two elseif. Can someone point me in the right direction?
I have done some fixes and it works for some operations. But I haven't tested it for all cases. Also, operations are only integers, no floats (e.g. check last output below).
class evaluateString:
def evalString(self,expression):
valueStack = []
opStack = []
i=0
while(i<len(expression)):
if(expression[i] == ' '):
continue
if(expression[i]>='0' and expression[i] <= '9'):
charNumber = [] #for storing number
j = i
while(j<len(expression) and expression[j]>='0' and expression[j] <= '9'):
charNumber.append(expression[j])
j += 1
i = (j-1)
valueStack.append(int(''.join(charNumber)))
elif (expression[i]=='('):
opStack.append(expression[i])
elif (expression[i]==')'):
while(opStack[-1]!='('):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.pop()
elif(expression[i]=='+'or expression[i]=='-'or expression[i]=='*'or expression[i]=='/'):
while( (len(opStack)!=0) and ( self.opPrecedence(expression[i],opStack[-1]) ) ):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.append(expression[i])
i = i + 1
while(len(opStack)!=0):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
return valueStack.pop()
def applyOperation(self,op,a,b):
if op=='+':
return a+b
elif op=='-':
return b-a
elif op=='*':
return a*b
elif op=='/':
return b/a
else:
return 0
def opPrecedence(self,op1,op2):
if (op2 == '(' or op2 == ')'):
return False
if ((op1 == '*' or op1 == '/') and (op2 == '+' or op2 == '-')):
return False
else:
return True
a = evaluateString()
print(a.evalString("8*12")) #prints 96
print(a.evalString("(122-434)")) #prints -312
print(a.evalString("(232+12)/2")) #print 122
print(a.evalString("232/12+2")) #prints 21
In python eval() will evaluate infix expressions
print(eval("(5+7)/2"))
it will print the evaluated infix expression value as 6.

Solving split string in python without the use of split() function

Faced an interview question in Python that was as follow?
ex:
input = ('192.168.15.1', '.', -1) ===> output = (192, 168, 15, 1)
input = ('192.168.15.1', '.', 2) ===> output = ( 192, 168, 15.1 )
Solve such that input(string,char,integer) will give the output such that the string is splited by the character and if integer is 0 or less than that else string is splited the number of by character where character split only occur for the value of integer.
I have written the code although it works fine within boundary and no error condition. Is there a better code out there plese share.
Thanks
def split_string(string,ch,inte):
q = string
c = ch
i = inte
s =list(q)
#Check if integer value is negative or positive
if i <= 0:
# split the string one time
r1 = split_once(s,c)
print r1
else:
#split according to the integear value
r2 = split_acc_intger(s,c,i)
print r2
def split_once(s,c):
y = 0
d = []
for x in range(len(s)):
if s[x] == c:
p=s[y:x]
d.append(''.join(p))
y = x + 1
elif x == len(s)-1:
p=s[y:]
d.append(''.join(p))
return d
def split_acc_intger(s,c,i):
y = 0
d =[]
count = 1
for x in range(len(s)):
# the leat number will 1
if s[x] == c:
p=s[y:x]
d.append(''.join(p))
y = x + 1
count += 1
elif count == i :
p=s[y:]
d.append(''.join(p))
break
return d
Simple and recursive.
def split_str(s,c,i):
if i == 0:
return [s]
else:
head, _, rest = s.partition(c)
if rest:
return [head] + split_str(rest, c, i - 1)
return [head]
def split(text, sep, maxsplit=-1):
parts = []
end = -1
while True:
start = end + 1
end = text.find(sep, start)
if (end == -1) or (maxsplit == 0):
parts.append(text[start:])
break
else:
parts.append(text[start:end])
if maxsplit != 0: maxsplit -= 1
return parts
print(split('192.168.15.1', '.', -1)) # ['192', '168', '15', '1']
print(split('192.168.15.1', '.', 2)) # ['192', '168', '15.1']
Something like this would work:
def splitter(string_, splitchar, maxsplits):
# if maxsplits is positive, split string into maxsplits of parts, on splitchar.
# Otherwise perform as many splits as the string allows.
out = []
sub = []
for ch in string_:
if ch != splitchar:
sub.append(ch)
else:
if maxsplits < 1 or (maxsplits > 0 and (len(out) < maxsplits)):
out.append(''.join(sub))
sub = []
else:
sub.append(ch)
out.append(''.join(sub))
return tuple(out)
>>> splitter.splitter('192.168.15.1', '.', -1)
('192', '168', '15', '1')
>>> splitter.splitter('192.168.15.1', '.', 2)
('192', '168', '15.1')
>>> splitter.splitter('192.168.15.1', '.', 0)
('192', '168', '15', '1')
>>> splitter.splitter('192.168.15.1', '.', 1)
('192', '168.15.1')
another simpler and short approach is you can use regular expressions like this:
import re
def split_without_using_split_fn(s, c, i):
if i<=0:
print(re.findall("[^"+c+"]+(?=\\"+c+"|$)", s))
else:
l=re.findall("[^"+c+"]+(?=\\"+c+"|$)", s)
print(l[0:-i]+[c.join(l[i:])])
split_without_using_split_fn(*('192.168.15.1', '.', -1))
split_without_using_split_fn(*('192.168.15.1', '.', 2))
Output:
$ python3 p.py
['192', '168', '15', '1']
['192', '168', '15.1']
$
You could solve this task with following function
def split_string(istr,ich,inte):
res = []
prev = 0
for i,ch in enumerate(istr):
if ch == ich:
res.append(istr[prev:i])
prev = i+1
inte = inte-1
if inte == 0:
break
if prev < len(istr):
res.append(istr[prev:])
return res
or another solution
def split_string(istr,ich,inte):
res = []
h,_,r = istr.partition(ich)
while r:
res.append(h)
inte = inte-1
if inte == 0:
h = r
break
h,_,r = r.partition(ich)
if h:
res.append(h)
return res
For following code
print split_string('192.168.15.1', '.', -1)
print split_string('192.168.15.1', '.', 2)
output will be
['192', '168', '15', '1']
['192', '168', '15.1']

Stack calculator (postfix, Python)

The question I'm having problem on is calculating the postfix form expressions: for example, (1, 2, '+', 3, '*').
By calculating the expression using the following algorithm:
1. If the expression only contains an integer, return that integer.
2. Otherwise, maintain a stack. Loop through the tuple and push every element to the stack. If the element is an operator, pop the first two element out of the stack, calculate the result and push the result into the stack.
To illustrate, we take the example above. Initially, the stack is empty.
The test case is
calculate((1, 2, '*', 3, '-', 2, '*', 5, '+'))
3
whereas my first code was no good (hardcoded and all >< ):
def calculate(inputs):
if len(inputs) ==1:
return inputs[0]
elif len(inputs) == 5:
s= []
push_stack(s, inputs[0])
push_stack(s, inputs[1])
if inputs[2] == '*':
A = s.pop() * s.pop()
elif inputs[2] == '+':
A = s.pop() + s.pop()
elif inputs[2] == '-':
A= s.pop() - s.pop()
elif inputs[2] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[3])
if inputs[4] == '*':
A = s.pop() * s.pop()
elif inputs[4] == '+':
A = s.pop() + s.pop()
elif inputs[4] == '-':
A= s.pop() - s.pop()
elif inputs[4] == '/':
A = s.pop() / s.pop()
return A
else:
s= []
push_stack(s, inputs[0])
push_stack(s, inputs[1])
if inputs[2] == '*':
A = s.pop() * s.pop()
elif inputs[2] == '+':
A = s.pop() + s.pop()
elif inputs[2] == '-':
A= s.pop() - s.pop()
elif inputs[2] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[3])
if inputs[4] == '*':
A = s.pop() * s.pop()
elif inputs[4] == '+':
A = s.pop() + s.pop()
elif inputs[4] == '-':
A= s.pop() - s.pop()
elif inputs[4] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[5])
if inputs[6] == '*':
A = s.pop() * s.pop()
elif inputs[6] == '+':
A = s.pop() + s.pop()
elif inputs[6] == '-':
A= s.pop() - s.pop()
elif inputs[6] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[7])
if inputs[8] == '*':
A = s.pop() * s.pop()
elif inputs[8] == '+':
A = s.pop() + s.pop()
elif inputs[8] == '-':
A= s.pop() - s.pop()
elif inputs[8] == '/':
A = s.pop() / s.pop()
return A
Sorry for making you read that! Then I changed the style to
def calculate(inputs):
if len(inputs) ==1:
return inputs[0]
else:
s =[]
for i in inputs:
if type(i) == int:
return push_stack(s, i)
elif i is '*' or '/' or 'x' or '+':
A = s.pop()
B =s.pop()
know = operator(i, A, B)
C = push_stack(s, know)
return C
def operator(sign, one, two):
if sign == '*':
A = one * two
elif sign == '+':
A = one + two
elif sign == '-':
A= one - two
elif sign == '/':
A = one / two
return A
Am I getting closer to the idea and how does my code improve?
** Edit **
Using IDLE:
>>> calculate((1, 2, '*', 3, '-'))
[1]
>>> calculate((1, 2, '+', 3, '*'))
[1]
>>> calculate((1, 2, '*', 3, '-', 2, '*', 5, '+'))
[1]
which is not the answer I'm looking for. It should be 1 then 9 then 3.
There is a problem with
elif i is '*' or '/' or 'x' or '+':
which is treated as
elif (i is '*') or ('/') or ('x') or ('+'):
which is not what you want (it's always true). You can instead use something like:
elif i in ('*', '/', 'x', '+'):
Also:
if type(i) == int:
return push_stack(s, i)
You shouldn't be returning there. You simply want:
if type(i) == int:
push_stack(s, i)
Lastly, I think a better approach would be to always use the stack, and just return the top of the stack at the end of your function. This saves you from having to create a special case for 1-element arguments to calculate(). Putting this all together, something along the lines of this should work:
def calculate(inputs):
stack = []
for a in inputs:
if type(a) is int:
stack.append(a)
continue
op1, op2 = stack.pop(), stack.pop()
if a == '+':
stack.append(op2 + op1)
elif a == '-':
stack.append(op2 - op1)
elif a == '*':
stack.append(op2 * op1)
elif a == '/':
stack.append(op2 / op1)
return stack.pop()
Right now this does no error-checking (e.g. for malformed expressions), but it's easy to add.
Part of the problem, which you seem to have realized, is that you are trying to make one function do everything. If you take a look at what the code is doing, and try to separate out the responsibilities, you end up with something like the following:
There are some crucial differences between Python 2.x and 3.x. Where these differences would cause problems, it's easiest to introduce helper functions and define them appropriately for each version:
import sys
if sys.hexversion < 0x3000000:
# Python 2.x
is_str = lambda s: isinstance(s, basestring)
inp = raw_input
else:
# Python 3.x
is_str = lambda s: isinstance(s, str)
inp = input
You do a fair bit of stack maintenance; this can be avoided by making a Stack class which knows how to pop and push multiple items. (It should also help your out-of-order arguments problem; 4 2 - should be 4 - 2, not 2 - 4)
class Stack(list):
def pop_n(self, n):
"""
Pop n items off stack, return as list
"""
assert n >= 0, "Bad value {}: n cannot be negative".format(n)
if n == 0:
return []
elif n <= len(self):
res = self[-n:]
del self[-n:]
return res
else:
raise ValueError("cannot pop {} items, only {} in stack".format(n, len(self)))
def push_n(self, n, items):
"""
Push n items onto stack
"""
assert n == len(items), "Expected {} items, received {}".format(n, len(items))
self.extend(items)
Rather than having a single "do-any-operation" function, we can let each operator have its own self-contained code. This makes it much easier to change or add operators without funny side-effects. First we make an Operator class
class Op:
def __init__(self, num_in, num_out, fn):
"""
A postfix operator
num_in: int
num_out: int
fn: accept num_in positional arguments,
perform operation,
return list containing num_out values
"""
assert num_in >= 0, "Operator cannot have negative number of arguments"
self.num_in = num_in
assert num_out >= 0, "Operator cannot return negative number of results"
self.num_out = num_out
self.fn = fn
def __call__(self, stack):
"""
Run operator against stack (in-place)
"""
args = stack.pop_n(self.num_in) # pop num_in arguments
res = self.fn(*args) # pass to function, get results
stack.push_n(self.num_out, res) # push num_out values back
then we define the actual operators as
ops = {
'*': Op(2, 1, lambda a,b: [a*b]), # multiplication
'/': Op(2, 1, lambda a,b: [a//b]), # integer division
'+': Op(2, 1, lambda a,b: [a+b]), # addition
'-': Op(2, 1, lambda a,b: [a-b]), # subtraction
'/%': Op(2, 2, lambda a,b: [a//b, a%b]) # divmod (example of 2-output op)
}
Now that the support structure is in place, your evaluation function is simply
def postfix_eval(tokens):
"""
Evaluate a series of tokens as a postfix expression;
return the resulting stack
"""
if is_str(tokens):
# if tokens is a string, treat it as a space-separated list of tokens
tokens = tokens.split()
stack = Stack()
for token in tokens:
try:
# Convert to int and push on stack
stack.append(int(token))
except ValueError:
try:
# Not an int - must be an operator
# Get the appropriate operator and run it against the stack
op = ops[token]
op(stack) # runs Op.__call__(op, stack)
except KeyError:
# Not a valid operator either
raise ValueError("unknown operator {}".format(token))
return stack
and to make it easier to test, we can make it interactive:
def main():
while True:
expr = inp('\nEnter a postfix expression (or nothing to quit): ').strip()
if expr:
try:
print(" => {}".format(postfix_eval(expr)))
except ValueError as error:
print("Your expression caused an error: {}".format(error))
else:
break
if __name__=="__main__":
main()
This runs like
Enter a postfix expression (or nothing to quit): 1 2 * 3 -
=> [-1]
Enter a postfix expression (or nothing to quit): 1 2 + 3 *
=> [9]
Enter a postfix expression (or nothing to quit): 1 2 * 3 - 2 * 5 +
=> [3]
Enter a postfix expression (or nothing to quit): 5 2 /%
=> [2, 1]
If you are doing calculator, or something like that, you should use function eval().
It will return result of expression.

Modify reverse polish notation calculator?

I'm trying to modify this reverse polish notation calculator. I've done nearly all of it, but it's not printing the way I want and I can't figure out why. The source code is:
def op_pow(stack):
b = stack.pop(); a = stack.pop()
stack.append(a ** b)
def op_mul(stack):
b = stack.pop(); a = stack.pop()
stack.append(a * b)
def op_div(stack):
b = stack.pop(); a = stack.pop()
stack.append(a / b)
def op_add(stack):
b = stack.pop(); a = stack.pop()
stack.append(a + b)
def op_sub(stack):
b = stack.pop(); a = stack.pop()
stack.append(a - b)
def op_num(stack, num):
stack.append(num)
ops = {
'^': op_pow,
'*': op_mul,
'/': op_div,
'+': op_add,
'-': op_sub,
}
def get_input(inp):
tokens = inp.strip().split()
return tokens
def rpn_calc(tokens):
stack = []
table = []
for token in tokens:
if token in ops:
ops[token](stack)
table.append( (token, ' '.join(str(s) for s in stack)) )
else:
op_num(stack, eval(token))
table.append( (token, ' '.join(str(s) for s in stack)) )
return table
rp = rpn_calc(get_input((raw_input())))
print rp
So if I input:
5 5 +
then the output is:
[('5', '5'), ('5', '5 5'), ('+', '10')]
and ideally I want the output to be just:
10
I think the brackets might be there because it's in a list but I'm not sure.
Thanks!
Table looks like it stores a list containing the evolving state. Instead of returning table from your rpn_calc function, it sounds like you want to just return the top of the stack.

python maze recurrsion not recurssing

I'm trying to solve a maze recursively and I can get it to go where I want it to (check to make sure it can go a way and then to mark it as been there) but for some reason when it runs into a dead end, it does not recursively go back to an open place to check another path. Is there anything wrong with the way I'm using recursion?
class maze(object):
def __init__(self, maze):
self.maze = maze
self.maze2d = []
n = 0
i = 0
for row in self.maze:
self.maze2d.append([])
print(row)
for col in row:
self.maze2d[i].append(col)
i += 1
print(self.maze2d)
def find_start(self):
x = 0
y = 0
for row in self.maze2d:
for index in row:
if index == "S":
self.maze2d[x][y] = index
return x,y
y += 1
x += 1
y = 0
return -1
def mazeSolver(self,x,y,path):
if self.maze2d[x][y] == "E":
return True
else:
if self.maze2d[x] != 0:
if self.maze2d[x+1][y] == ".":
self.maze2d[x+1][y] = "_"
self.mazeSolver(x+1,y,path + "S")
if self.maze2d[x] < len(self.maze2d):
if self.maze2d[x-1][y] == ".":
self.maze2d[x-1][y] = "_"
self.mazeSolver(x-1,y,path + "N")
if y < len(self.maze2d[x]):
if self.maze2d[x][y+1] == ".":
self.maze2d[x][y+1] = "_"
self.mazeSolver(x,y+1,path + "E")
if self.maze2d[y] != 0:
if self.maze2d[x][y-y] == ".":
self.maze2d[x][y-1] = "_"
self.mazeSolver(x,y-1,path + "W")
and where I'm calling the function and the maze itself:
from eachstep import *
maze1 = []
maze1.append("S..*..")
maze1.append("*...*.")
maze1.append("..*..E")
var1 = maze(maze1)
x,y = var1.find_start()
var1.mazeSolver(x,y,"")
I changed your mazeSolver function with this. And I print the path at the end:
def mazeSolver(self,x,y,path):
if self.maze2d[x][y] == '.':
self.maze2d[x][y] = "_"
if self.maze2d[x][y] == "E":
print path
return True
else:
if x < len(self.maze2d)-1:
if self.maze2d[x+1][y] in ['.','E']:
self.mazeSolver(x+1,y,path + "S")
if x > 0:
if self.maze2d[x-1][y] in ['.','E']:
self.mazeSolver(x-1,y,path + "N")
if y < len(var1.maze2d[x])-1:
if self.maze2d[x][y+1] in ['.','E']:
self.mazeSolver(x,y+1,path + "E")
if y > 0:
if self.maze2d[x][y-y] in ['.','E']:
self.mazeSolver(x,y-1,path + "W")
>>> var1.mazeSolver(x,y,"")
ESEESEE
>>>> var1.maze2d
[['S', '_', '_', '*', '.', '.'],
['*', '_', '_', '_', '*', '.'],
['_', '_', '*', '_', '_', 'E']]
Your code will never reach the end, since it only visits locations with the value ., and the end has the value E.

Categories