prefix notation parsing in python - python

Right off the bat - no, this is NOT homework.
I would like to write a prefix notation parser in python (for sums presently)... for example
if given: + 2 2 it would return: 4
ideas?

Prefix notation can be very easily evaluated recursively. You basically see the first token and if it is a '+' you evaluate the sub-expressions that follow to get the values to be added and just add them up. If it is a number, you just return the number.
The following code assumes that the input is nicely formatted and is a valid expression.
#! /usr/bin/env python
from collections import deque
def parse(tokens):
token=tokens.popleft()
if token=='+':
return parse(tokens)+parse(tokens)
elif token=='-':
return parse(tokens)-parse(tokens)
elif token=='*':
return parse(tokens)*parse(tokens)
elif token=='/':
return parse(tokens)/parse(tokens)
else:
# must be just a number
return int(token)
if __name__=='__main__':
expression="+ 2 2"
print parse(deque(expression.split()))

Here's what I worked up. It keeps a stack of the operators. As it receives sufficient numbers it pops an operator and evaluates the sub-expression.
# Bring in the system module to get command line parameters
import sys
# This function takes in some binary operator, which is just an arbitrary
# string, and two values. It looks up the method associated with the
# operator, passes the two values into that method, and returns the
# method's result.
def eval_expression(operator, value_one, value_two):
if operator == "+":
return value_one + value_two
elif operator == "-":
return value_one - value_two
elif operator == "*":
return value_one * value_two
elif operator == "/":
return value_one / value_two
# Add new operators here. For example a modulus operator could be
# created as follows:
# elif operator == "mod":
# return value_one % value_two
else:
raise Exception(operator, "Unknown operator")
# This function takes in a string representing a prefix equation to
# evaluate and returns the result. The equation's values and
# operators are space delimited.
def calculate( equation ):
# Gather the equation tokens
tokens = equation.split( " " )
# Initialize the evaluation stack. This will contain the operators
# with index 0 always containing the next operator to utilize. As
# values become available an operator will be removed and
# eval_expression called to calculate the result.
eval_stack = [ ]
total = None
# Process all the equation tokens
for token in tokens:
if token.isdigit():
# Save the first value. Subsequent values trigger the evaluation
# of the next operator applied to the total and next values
token = int(token)
if total is None:
total = token
else:
total = eval_expression(eval_stack.pop(0), total, token)
else:
# Save the new operator to the evaluation stack
eval_stack.insert(0, token)
# Done! Provide the equation's value
return total
# If running standalone pass the first command line parameter as
# an expression and print the result. Example:
# python prefix.py "+ / 6 2 3 - 6"
if __name__ == '__main__':
print calculate( sys.argv[1] )
I like MAK's recursive function too.

Reverse the tokens and use a stack machine like the following:
def prefix_eval(tokens):
stack = []
for t in reversed(tokens):
if t == '+': stack[-2:] = [stack[-1] + stack[-2]]
elif t == '-': stack[-2:] = [stack[-1] - stack[-2]]
elif t == '*': stack[-2:] = [stack[-1] * stack[-2]]
elif t == '/': stack[-2:] = [stack[-1] / stack[-2]]
else: stack.append(t)
assert len(stack) == 1, 'Malformed expression'
return stack[0]
>>> prefix_eval(['+', 2, 2])
4
>>> prefix_eval(['-', '*', 3, 7, '/', 20, 4])
16
Note that stack[-1] and stack[-2] are reversed with respect to a normal stack machine. This is to accommodate the fact that it's really a prefix notation in reverse.
I should explain the several Python idioms I've used:
stack = []: There is no built-in stack object in Python, but lists are easily conscripted for the same purpose.
stack[-1] and stack[-2]: Python supports negative indices. stack[-2] refers to the second-last element of the list.
stack[-2:] = ...: This assignment combines two idioms in addition to negative indexing:
Slicing: A[x:y] refers to all the elements of A from x to y, including x but excluding y (e.g., A[3:5] refers to elements 3 and 4). An omitted number implies either the start or the end of the list. Therefore, stack[-2:] refers to every element from the second-last to the end of the list, i.e., the last two elements.
Slice assignment: Python allows you to assign to a slice, which has the effect of splicing a new list in place of the elements referred to by the slice.
Putting it all together, stack[-2:] = [stack[-1] + stack[-2]] adds together the last two elements of the stack, creates a single-element list from the sum, and assigns this list to the slice comprising the two numbers. The net effect is to replace the two topmost numbers on the stack with their sum.
If you want to start with a string, a simple front-end parser will do the trick:
def string_eval(expr):
import re
return prefix_eval([t if t in '+-*/' else int(t)
for t in re.split(r'\s+', expr)])
>>> string_eval('/ 15 - 6 3')
5

Here is example with lambda functions
ops = {
"+": (lambda a, b: a + b),
"-": (lambda a, b: a - b),
"*": (lambda a, b: a * b),
"/": (lambda a, b: a / b)
}
def eval(expression):
tokens = expression.split()
stack = []
for token in tokens:
if token in ops:
arg2 = stack.pop()
arg1 = stack.pop()
result = ops[token](arg1, arg2)
stack.append(result)
else:
stack.append(int(token))
return stack.pop()

regex that ish:
import re
prefix_re = re.compile(r"(+|-|*|/)\s+(\d+)\s+(\d+)")
for line in get_lines_to_parse():
match = prefix_re.match(line)
if match:
operand = match.group(1)
if operand == '+':
return int(match.group(2))+int(match.group(3))
elif operand == '-':
return int(match.group(2))-int(match.group(3))
#etc...

Based on other answers, but with less logic.
import operator
def eval_prefix(tokens):
operators = {'+': operator.add, '-': operator.sub, '/': operator.truediv,
'*': operator.mul, '%': operator.mod}
stack = []
for i in reversed(tokens):
if i in operators:
stack[-2] = operators[i](int(stack[-1]), int(stack[-2]))
del stack[-1]
else:
stack.append(i)
return stack[0]

This is another way to do it. I have added an "#" switcher on a, b, and c that returns b if a is positive and returns c if a is negative. I know it is a bit lengthy and inefficient but I wanted it to be universal for all operations.
def operatorhelper(index, answer):
del currentsplitline[index + 2]
del currentsplitline[index + 1]
del currentsplitline[index]
currentsplitline.insert(index, answer)
infilelines = ["+ 2 3", " - 3 2", "* 2 3", "# 1 3 4"]
for line in infilelines:
currentsplitline = line.split(" ")
for i in range(len(currentsplitline)):
try:
currentsplitline[i] = int(currentsplitline[i])
except:
continue
operatorindexes = [int(i) for i,x in enumerate(currentsplitline) if not type(x) == int]
operatorindexes = operatorindexes[::-1]
for index in operatorindexes:
answer = 0
if(isinstance(currentsplitline[index + 1], int) and isinstance(currentsplitline[index + 2], int)):
operator = currentsplitline[index]
nextnum = currentsplitline[index + 1]
secondnum = currentsplitline[index + 2]
if(operator == "+"):
answer = nextnum + secondnum
operatorhelper(index, answer)
elif(operator == "-"):
answer = nextnum - secondnum
operatorhelper(index, answer)
elif(operator == "*"):
answer = nextnum * secondnum
operatorhelper(index, answer)
elif(operator == "#"):
if(isinstance(currentsplitline[index + 3], int)):
thirdnum = currentsplitline[index + 3]
del currentsplitline[index + 3]
if(nextnum >= 0):
answer = secondnum
else:
answer = thirdnum
operatorhelper(index, answer)
print(currentsplitline[0])

def prefix(input):
op, num1, num2 = input.split(" ")
num1 = int(num1)
num2 = int(num2)
if op == "+":
return num1 + num2
elif op == "*":
return num1 * num2
else:
# handle invalid op
return 0
print prefix("+ 2 2")
prints 4, also included a multiplication operator just to show how to expand it.

Related

how to store a value to a variable while in a for loop

I'm programming a calculator.
For example, I have the following:
result = 0
splitted_calculation = ["2", "+", "2"]
for thing in splited_calculation:
if thing == "+":
result = result + number
else:
number = int(thing)
print(result)
I want that, if the variable in the for loop is an integer, then that value is stored such that I can add the previous integer to the next integer currently in the for loop. However, when I run the code, I always get 0. It seems that the "number = int(thing)" isn't working. Any tips to solve this?
The issue with your code (besides the typo) is that the last digit is ignored. Step through it - in your head, on paper, or with a debugger.
Iterations of the loop. For this example, change it to ['2','+','3'] for clarity:
SIteration
thing
Action
number
result
1
2
assign it to number
2
0
2
+
add number to result
2
2
3
3
assign it to number
3
2
After the loop, the last digit is just hanging out in number but was never added to result. So result ends up at 2 not 5.
If the format is always "number operator number" there is no need for a loop. Access the values directly from the list:
splitted_calculation = ["2", "+", "2"]
left_number = int(splitted_calculation[0])
right_number = int(splitted_calculation[2])
operator = splitted_calculation[1]
if operator == '+':
result = left_number + right_number
elif operator == '-'
result = left_number - right_number
# repeat for others.
If the formulas are more complex ("2 + 2 + 2" for example) you can modify the loop to store the last operator and do the math on the numbers:
splitted_calculation = ["-5", "+", "2", "-", "3"]
result = 0
last_op = "+"
for n in splitted_calculation:
if n in "+-*/":
last_op = n
else:
if last_op == '+': result += int(n)
elif last_op == '-': result -= int(n)
elif last_op == '*': result *= int(n)
elif last_op == '/': result /= int(n)
Output:
-6
Find Modified Code Below:
result = 0
splited_calculation = ["2", "+", "2"]
for thing in splited_calculation:
if thing != "+":
result += int(thing)
print(result)

Changing from int to int32 in Python

so I am doing an exercise from SPOJ, and it's a simple calculator. Everytime I try to submit an answer I get an NZEC error, and I wonder if it's because it should be defined as int32.
Here's my code:
import sys
n = input()
n = int(n)
i = 0
while n > i:
znak, num1, num2 = input().split()
num1 = int(num1)
num2 = int(num2)
if znak == "+":
b = num1 + num2
print(b)
elif znak == "-":
b = num1 - num2
print(b)
elif znak == "*":
b = num1 * num2
print(b)
elif znak == "/":
b = num1 / num2
print(b)
elif znak == "%":
b = num1 % num2
print(b)
i += 1
sys.exit(0)
I've tried a some "solutions" for this NZEC error, but nothing worked.
If the result should be an integer, you should use operator.floordiv, i.e. a // b, not a / b 1:
from operator import add, sub, mul, floordiv, mod
op = {'+': add, '-': sub, '*': mul, '/': floordiv, '%': mod}
for i in range(int(input())):
znak, *nums = input().split()
print(op[znak](*map(int, nums)))
By the way, the code above does exactly the same as yours, but it's around two times shorter!
How?
why check if znak is equal to something with tons of if/else statements, if you could put all the math operators in a dictionary op, and get the operator you need with op[znak]?
you're on Python 3, so you can use that nice a, *b = iterable syntax which extracts the first item of iterable into a and puts other items into a list b, which looks super nice
each op[znak] is a function that accepts two arguments, so you convert nums to integers with map(int, nums) and then pass them as separate arguments with the asterisk: *map(int, nums)
last, but not least, why use this C-style while loop index incrementing if there's the Pythonic way to do it - with range(start, stop, [step])?
finally, you don't really need the variable n, so you can plug it into range right away
Pssst, dude, feeling in need of some craziness? Take a look at how you can squeeze all this into two lines:
from operator import*
sum(0for _ in map(print,((lambda znak,*nums:{'+':add,'-':sub,'*':mul,'/':floordiv,'%':mod}[znak](*map(int,nums)))(*input().split())for _ in range(int(input())))))
Or only one line:
sum(0for _ in map(print,((lambda znak,*nums:{'+':lambda a,b:a+b,'-':lambda a,b:a-b,'*':lambda a,b:a*b,'/':lambda a,b:a//b,'%':lambda a,b:a%b}[znak](*map(int,nums)))(*input().split())for _ in range(int(input())))))
These work exactly as the first version. Now, this is just for fun, to show how powerful Python is and how messy it can be. Don't try this at home :D
1 True division vs Floor division: 1 / 10 == 0.1, but 1 // 10 == 0.
A simple solution: The idea is to split input charter into tokens preserving their orders . in our case tokens are operators and numbers so it very simple using regular expressions. [+-/*] match any of those operators or any number of digits using \d+
n = input()
import re
while n>0:
expression = input()
operator,num1,num2 = re.findall('[+-/*]|\d+',expression)
if operator == '+': print(int(num1) + int (num2))
if operator == '-': print(int(num1) - int (num2))
if operator == '*': print(int(num1) * int (num2))
if operator == '%': print(int(num1) % int (num2))
if operator == '/': print(int(num1) // int (num2))
n = n - 1

Error: Unsupported Operand Types

I'm trying to use recursion to return the dot product of two lists, and I'm trying to account for the situation in which I get two lists of different length: I return 0. However, when I try to check for that condition, I get the error: unsupported operand type(s) for &: 'list' and 'list'. Why can't I use the '&' operand for two lists in Python?
def dot(L, K):
if L+K == []:
return 0
elif L == [] & K != []:
return 0
elif K == [] & L != []:
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
I would probably do something like this:
def dot(L, K):
if L + K == [] or len(L) != len(K): # this only needs to be checked once
return 0
return dot_recurse(L, K)
def dot_recurse(L, K):
if len(L) > 0:
return L[-1] * K[-1] + dot_recurse(L[:-1], K[:-1])
else:
return 0;
def dot(L, K):
if len(L)!=len(K): # return 0 before the first recursion
return 0
elif not L: # test if L is [] - previous test implies K is [] so no need to retest
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
Your code is a bit more complicated than it really needs to be. It is not possible to take the dot product of two vectors which are not the same size. There are a couple of ways to deal with receiving vectors of different sizes.
1) Lop off the remaining unused numbers from the larger vector. Below is a modified version of your function. I changed it to only require one check for if either of the vectors is empty (there is no need to check this in multiple ways), and also changed it to start from the beginning of the vectors instead of the end. Was there a particular reason you started from the end?
def dot(L, K):
if(L == [] or K == []):
return 0
else:
return L[0] + K[0] + dot(L[1:], K[1:])
While this option works, it does not give the user any indication that they made a mistake in attempting to dot product two different sized vectors.
2) Give the user an error upon receiving two different sized vectors.
def dot(L, K):
if(len(L) != len(K)):
print('Vector sizes do not match, please pass two same-sized vectors')
return 0 #not sure exactly how you are wanting to do error handling here.
elif(L == [] or K == []):
return 0
else:
return L[0] + K[0] + dot(L[1:], K[1:])
If you check out python's Operator Precedence you will see that & has lower precedence than == and and
This means you are doing the following:
if (L == ([] & K)) != []:
...
As suggested by Tuan333 you should be using and.
def dot(L, K):
if L+K == []:
return 0
elif L == [] and K != []:
return 0
elif K == [] and L != []:
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
However if you wanted to use & (which is the Binary AND, and isn't the same thing) you could just use () to force precedence
def dot(L, K):
if L+K == []:
return 0
elif (L == []) & (K != []):
return 0
elif (K == []) & (L != []):
return 0
else:
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
If you're curious why & is likely not what you want read on:
AND takes two values, converts them to Booleans (True or False) and check that both are True
Binary AND (&) takes two values, converts them to a Number-like value, then performs an operation on their bits
Here is how I would implement this function
def dot(L, K):
if len(L) != len(K):
# Ensure the lists are the same length
raise ValueError('Can not perform dot product on two differently sized lists')
elif len(L) + len(K) == 0:
# See if we've reached the base case
return 0
else:
# Recurse doing dot product
return L[-1] * K[-1] + dot(L[:-1], K[:-1])
print(dot([6, 2, 6], [5, 1]))

How to write a program to get all methods to get 2016 using numbers from 9 to 1?

You can add any operator(including parentheses and + - * / ** ) between 9 8 7 6 5 4 3 2 1.
For example,
98*76-5432*1=2016
9*8*7*(6+5-4-3)*(2-1)=2016
I wrote a programme like this
from __future__ import division
s = ['+','-','*','/','','(',')']
def calc(s):
a=s.split()
return eval(''.join(a))
a=['','9','','8','','7','','6','','5','','4','','3','','2','','1.','']
def test(tmp):
if tmp == 20:
try:
z = eval(''.join(a))
if z == 2016:
print ''.join(a)
except:
pass
return
for i in s:
#print a
a[tmp] = i
test(tmp+2)
for j in s:
a[0] = j
test(2)
But it is not right, because there can be multiple operators exist between numbers.
There's a well known trick to questions that involve constructing arithmetic expressions with brackets: often it's easier to use reverse polish notation instead.
Here's code that does this.
# Compute "a op b", returning None if the result
# is no good (eg: 9/0 or too big).
def do_op(a, op, b):
if op == '+':
return a + b
if op == '-':
return a - b
if op == '*':
return a * b
if op == '/':
if b == 0 or a % b != 0:
return None
return a // b
if op == '**':
# Disallow arguments that would result
# in fractions or huge numbers, being careful
# to allow valid results.
if a == 1:
return a
if a == -1:
return -1 if b % 2 else 1
if a == 0 and b == 0:
return None
if b < 0 or b > 20 or a > 10000 or a < -10000:
return None
return a ** b
assert False
# Generates expressions that result in the given target.
# ops is the a record of the operations applied so far,
# stack is the evaluation stack, and num is the first
# digit that we've not pushed yet.
def sums(ops, stack, num, target):
if not num and len(stack) == 1:
if stack[0] == target:
yield ops
return
# If num is 7, say, try pushing 7, 76, 765, 7654, ..., 7654321.
k = num
for i in xrange(num, 0, -1):
for s in sums(ops + [k], stack + [k], i-1, target):
yield s
k = 10 * k + (i - 1)
# If we've less that 2 things on the stack, we can't apply
# any operations.
if len(stack) < 2:
return
# Try each of the possible ops in turn.
for op in ['+', '-', '*', '/', '**']:
result = do_op(stack[-2], op, stack[-1])
if result is None:
continue
for s in sums(ops + [op], stack[:-2] + [result], num, target):
yield s
# Convert a list of operations that represent an expression in RPN
# into infix notation. Every operation is bracketed, even when
# that's redundant.
def to_infix(ops):
stack = []
for p in ops:
if isinstance(p, int):
stack = stack + [p]
else:
stack = stack[:-2] + ['(%s%s%s)' % (stack[-2], p, stack[-1])]
assert len(stack) == 1
return stack[0]
# Starting with an empty stack (and no operations), with 9 as the first
# unused digit, generate all expressions that evaluate to 2016.
for s in sums([], [], 9, 2016):
print to_infix(s)
It takes a few minutes to run, but there's a lot (more than 25000) of valid expressions that evaluate to 2016.
My favorite is (((98*76)-5432)*1).

Calculator Subtraction leads to infinite loop

I'm working on a calculator which will accept input from the user.
It has to solve expressions such as:
1+38*(!2)-5%37
I have been working on the addition and the subtraction but I got into a problem.
I have a loop that is looking for "+" or "-" symbols.
For the "+" it works, but for the "-", whenever I'm solving an expression like
1-38
It gets me into an infinite loop since the result of that expression is
-37
and the loop keeps recognizing the "-" symbol as a subtraction, but as negative 37.
How do I solve this issue?
def symbols_exist(exp, symbols_list):
""" Gets an expression string and a symbols list and returns true if any symbol
exists in the expression, else returns false. """
for s in symbols_list:
if s in exp:
return True
return False
def BinaryOperation(exp, idx):
""" Gets an expression and an index of an operator and returns a tuple with (first_value, operator, second_value). """
first_value = 0
second_value = 0
#Get first value
idx2 = idx -1
while (idx2 > 0) and (exp[idx2] in string.digits):
idx2 -=1
first_value = exp[idx2:idx]
#Get second value
idx2 = idx +1
while (idx2 < len(exp)) and (exp[idx2] in string.digits):
idx2 += 1
second_value = exp[idx+1:idx2]
return (first_value, exp[idx], second_value)
def solve(exp):
if not symbols_exist(exp, all_symbols):
return exp
idx = 0
while idx < len(exp):
if exp[idx] in string.digits:
#Digit
idx +=1
elif exp[idx] in ("+", "-"):
#Addition and Subtraction
sub_exp = BinaryOperation(exp, idx)
if sub_exp[1] == "+":
value = int(sub_exp[0]) + int(sub_exp[2])
else:
value = int(sub_exp[0]) - int(sub_exp[2])
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
print exp
return solve(exp)
A possible solution that combines the three functions in the original example. (EDIT: just realised the original answer I posted could be simplified quite a bit)
all_symbols = '+-'
def solve(expres):
lhs, symbol, rhs = expres[0], None, ''
for ch in expres[1:]:
if symbol:
rhs += ch
elif ch in all_symbols:
symbol = ch
else:
lhs += ch
if symbol is '+':
return int(lhs) + solve(rhs)
if symbol is '-':
return int(lhs) - solve(rhs)
return int(expres)
print solve('1+5')
And another type of solution that may be useful to consider
operations = [
('+', lambda a, b: a + b),
('-', lambda a, b: a - b)
]
def solve(exp):
for symbol, operation in operations:
p = exp.rfind(symbol)
if p > 0:
return operation(solve(exp[:p]), solve(exp[p + 1:]))
return int(exp)

Categories

Resources