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.
Related
I have created the following pop function:
def pop(arr):
if not isempty(arr):
topelement = arr[len(arr)-1]
arr.remove(topelement)
return topelement
And it worked correctly until I used it in order to reverse order of a stack of numbers and operators:
"3 6 2 + * 14 3 4 + + /"
into
"/ + + 4 3 14 * + 2 6 3".
In first iteration of while loop shown below it pushed "/" operator to the auxiliary stack and deleted it from the top of entry, which is OK - but in the second iteration it deleted "+" sign from the middle of the entry instead of the plus sign with the highest index.
def evaluation(eq):
entryunsplit = errpostfix(eq)
entry = entryunsplit.split()
lengthofentry = len(entry)
stack = []
while len(stack) != lengthofentry:
push(stack,pop(entry))
Could someone please explain me why didn't it delete the last element and how can I avoid that error?
I am putting the whole code below in case some other element turns out to be significant.
stack1 = []
max_size = 30
def push(arr,a):
if len(arr) < max_size:
arr.append(a)
def isempty(arr):
if len(arr) == 0:
return True
else:
return False
def top(arr):
if not isempty(arr):
return arr[len(arr)-1]
def pop(arr):
if not isempty(arr):
topelement = arr[len(arr)-1]
arr.remove(topelement)
return topelement
def errpostfix(eq):
entry = eq.split()
opstack = []
exit = []
priorities = { "+": 1, "-": 1, "*": 0, "/": 0 }
for token in entry:
if token == "(":
push(opstack,token)
elif token == "*" or token == "/" or token == "+" or token == "-":
if top(opstack) == "*" or top(opstack) == "/" or top(opstack) == "+" or top(opstack) == "-":
while not isempty(opstack) and priorities[top(opstack)] >= priorities[token]:
push(exit,pop(opstack))
isempty(opstack)
push(opstack,token)
elif token == ")":
while top(opstack) != "(":
push(exit,pop(opstack))
pop(opstack)
else:
push(exit,token)
while not isempty(opstack):
push(exit, pop(opstack))
output = " ".join(exit)
return output
def isop(ch):
if ch == "+" or ch == "-" or ch == "*" or ch == "/":
return True
else:
return False
def evaluation(eq):
entryunsplit = "3 6 2 + * 14 3 4 + + /"
entry = entryunsplit.split()
lengthofentry = len(entry)
stack = []
while len(stack) != lengthofentry:
push(stack,pop(entry))
The remove() operation on a list will delete the first occurrence of an item in that list, is not "random" (check the docs). If there are several repeated elements, the first one encountered will be the one that gets deleted. To delete the last element, simply use the built-in pop() method:
def pop(arr):
if not isempty(arr):
topelement = arr[-1]
arr.pop()
return topelement
i've implemented the infix-to-prefix converter using stack , the power operator has right to left association , which drove me nuts trying to implement it.
here is my code :
def infix_to_postfix_converter(string):
def pop_untill_open_parentheses():
while not stack.is_empty() and stack.peek() != '(':
output.append(stack.pop())
stack.pop()
def pop_all_the_higher_precedences(operator):
while not stack.is_empty() and precedence(stack.peek()) >= precedence(operator):
if stack.peek() != '(':
output.append(stack.pop())
else:
break
stack.push(operator)
def precedence(operator):
operators = {'(': 3,
')': 3,
'^':2,
'*': 1,
'/': 1,
'+': 0,
'-': 0,
}
return operators[operator]
stack = Stack()
output = []
for literal in string:
if literal.isalpha():
output.append(literal)
elif literal == '(':
stack.push(literal)
elif literal == ')':
pop_untill_open_parentheses()
else:
pop_all_the_higher_precedences(literal)
while not stack.is_empty():
output.append(stack.pop())
return ''.join(output)
so the solution is , if there is a '^' in the stack and another '^' came to be pushed it'll be pushed on top of the first '^' without poping it .
my solution :
add this compare function:
def compare(operatora,operatorb):
if operatora==operatorb=='^':
return False
else:
return precedence(operatora)>=precedence(operatorb)
and modify the pop_all_the_higher_precedence function:
def pop_all_the_higher_precedences(operator):
while not stack.is_empty() and compare(stack.peek(),operator):
if stack.peek() != '(':
output.append(stack.pop())
else:
break
stack.push(operator)
So I am currently learning about postfix, prefix, and infix expressions; and one of the challenge questions was about evaluating infix expressions using stacks. I think I understand the concept of it. However, I am really puzzled as to why my operators are not pushing onto my stack. I believe the problem is within line 31. However, I am not sure as to why. Could someone help me find and fix the problem?
class Stack:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items) - 1]
def size(self):
return len(self.items)
def infix(equation):
prec_dictionary = {"(": 0, ")": 0, "^": 4, "*": 3, "/": 3, "+": 2, "-": 2, "<": 1, ">": 1}
operator_stack = Stack()
operand_stack = Stack()
allowed_operators = "+-/*^<>"
a_list = equation.split()
for i in a_list:
if i in allowed_operators:
if operator_stack.is_empty():
operator_stack.push(i)
else:
if prec_dictionary[i] > prec_dictionary[operator_stack.peek()]:
operator_stack.push(i)
if i == "(":
operator_stack.push(i)
elif i == ")":
while operator_stack.peek() != "(":
value1 = int(operand_stack.pop())
operator = operator_stack.pop()
value2 = int(operand_stack.pop())
value = compute(value1, value2, operator)
operand_stack.push(value)
operator_stack.pop()
else:
operand_stack.push(i)
return operand_stack.pop()
def compute(number1, number2, operator):
if operator == "+":
return number1 + number2
elif operator == "-":
return number1 - number2
elif operator == "*":
return number1 * number2
elif operator == "/":
return number1 / number2
elif operator == "^":
return number1 ** number2
elif operator == "<":
return min(number1, number2)
else:
return max(number1, number2)
print(infix('2 ^ ( 1 + 3 ^ 2 )'))
I learn about Reverse Polish Notation (:RPN).
I want to calculate Numerical formula by using RPN.
I managed to write following Program.
At a glance, this code work properly.
But, when I submitted this code to Programming Contest Site, (
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0109
) I got Wrong Answer.
What is wrong with my code?
# coding: utf-8
# Convert String to List
def String2List(s):
L = []
flag = True
l = len(s)
for i in range(l):
if s[i].isdigit() and flag:
t = ""
j = 0
while s[i+j].isdigit():
t += s[i+j]
if i+j == l-1:
break
j += 1
L.append(t)
flag = False
elif not s[i].isdigit():
L.append(s[i])
flag = True
return L
# generate Reverse Polish Notation
def RPN_list(L):
S, L2 = [], []
table = {"*": 1, "/": 1, "+": 0, "-": 0, "(": -1, ")": -1}
for i in L:
if i.isdigit():
L2.append(i)
elif i == "(":
S.append(i)
elif i == ")":
while S[-1] != "(":
L2.append(S.pop())
S.pop()
else:
if len(S) != 0 and (table[S[-1]] >= table[i]):
L2.append(S.pop())
S.append(i)
while len(S) != 0:
L2.append(S.pop())
return L2
# calculate Reverse Polish Notation
def RPN_cul(L):
St = []
for i in L:
if i == '+':
St.append(int(St.pop()) + int(St.pop()))
elif i == '-':
St.append(-int(St.pop()) + int(St.pop()))
elif i == '*':
St.append(int(St.pop()) * int(St.pop()))
elif i == '/':
a = int(St.pop())
b = float(St.pop())
St.append(b/a)
else:
St.append(i)
return St[0]
N = int(raw_input())
for i in range(N):
s = raw_input()
L = String2List(s[:-1])
L = RPN_list(L)
print int(RPN_cul(L))
Result
$ python reverse_polish_notation.py
2
4-2*3=
-2
4*(8+4+3)=
60
when I fixed as follows, It was accepted. Thanks to help me.
Before:
def RPN_list(L):
...
if len(S) != 0 and (table[S[-1]] >= table[i]):
L2.append(S.pop())
S.append(i)
...
After:
def RPN_list(L):
...
while len(S) != 0 and (table[S[-1]] >= table[i]):
L2.append(S.pop())
S.append(i)
...
polish_str="123*+4-"
#scan from left to right once you got the operator make the operation save the result again perform the operation
#result=3
polish_list=[]
for i in polish_str:
polish_list.append(i)
print(polish_list)
####
temp=[]
operator=['*',"+","/","-"]
def operation(o,a,b):
if o=="+":
result=a+b
if o=="-":
result=a-b
if o=="*":
result=a*b
if o=="/":
result=a/b
return result
for i,v in enumerate(polish_list):
if v in operator:
print(temp)
leng=len(temp)
arg1=temp.pop()
print("arg1==>",arg1)
arg2=temp.pop()
print("arg2==>",arg2)
result=operation(v,arg1,arg2)
print("result==>",result)
temp.append(result)
print("temp in iteration==>",temp)
else:
temp.append(i)
print("***final temp***",temp)
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.