Infix to Postfix using a stack w/Regex - python-3.x

I'm trying to figure out a homework assignment and I've run into a very specific weird problem. Basically I'm using regex to pull all of the operators and operands out one at a time in order of operations, and then pop them off a stack while printing them in the correct postfix notation. It works in most cases, however when running the unittest it fails test_infix14, test_infix_bad_expression, and test bad postfix. I can tell that it's something to do with the way + and - is coming out of the expression (I think) but I have no idea what's making it do it this way. Any help is appreciated. I thought I had this one good and done on Friday but this one little issue has occupied 2 whole days :P
''' Main Driver Code '''
import re
import stack
def eval_postfix(postfix):
''' Postfix '''
stac = stack.Stack()
tokens = re.findall(r'\d+|\+|\-|\*|\/', postfix)
if len(tokens) == 0:
raise ValueError
if len(tokens) < 2:
return float(tokens[0])
for toke in tokens:
if toke.isnumeric():
stac.push(float(toke))
else: # t is an operator
op1 = stac.pop() #operand 1
op2 = stac.pop() #operand 2
if toke == '+':
result = op2 + op1
elif toke == '-':
result = op2 - op1
elif toke == '*':
result = op2 * op1
elif toke == '/':
result = op2 / op1
stac.push(result)
return float(stac.pop())
def precedence(top, inputSymbol): # check if top has >= precedence than inputSymbol
''' Helper precedence function '''
if len(re.findall(r'\(|\)|\-|\+|\*|\/', top)) > 0: # if top of stack is an operator
prec = ['(', '-', '+', '*', '/', ')'] # ascending precedence
topPrec = prec.index(top) #e.g.: top == '+', then topPrec == 1
symbol_input = prec.index(inputSymbol)
#e.g.: inputSymbol == '/', then symbol_input == 4
return topPrec >= symbol_input #e.g.: 1 >= 4: false
return False
def in2post(infix):
result = ""
if infix == [None]:
raise ValueError
tokens = re.findall(r'\d+|\(|\)|\+|\-|\*|\/', infix)
stac = stack.Stack()
for t in tokens:
if t == '(':
stac.push(t)
elif t.isnumeric():
result += t + ' '
elif len(re.findall(r'\+|\-|\*|\/', t)) > 0:
while stac.size() > 0 and precedence(stac.peek(), t): #and s.peek() != '('
result += stac.pop() + ' '
stac.push(t)
else:
result += stac.pop() + ' '
while stac.peek() != '(':
result += stac.pop() + ' '
stac.pop()
while stac.size() > 0:
if stac.peek() != '(':
result += stac.pop() + ' '
return result
def main():
''' Main Function '''
with open("data.txt") as file:
for line in file.readlines():
print("infix: %s" % line, end='')
postfix = in2post(line)
print("postfix: %s" % postfix)
answer = eval_postfix(postfix)
print("answer: %s" % answer)
print()
if __name__ == '__main__':
main()
''' stack class '''
class Stack:
''' see above doc string '''
def __init__(self):
''' constructor '''
self.stack_array = []
def push(self, item):
''' add to the stack '''
self.stack_array.append(item)
def pop(self):
''' remove from the array '''
#try:
# return self.stack_array.pop()
#except IndexError:
# print(self.stack_array)
if len(self.stack_array) == 0:
raise IndexError
return self.stack_array.pop()
def peek(self):
''' See top item of array '''
#if self.stack_array == [')']:
# raise SyntaxError
if len(self.stack_array) == 0:
raise IndexError
return self.stack_array[-1]
def size(self):
''' get total size of array '''
return len(self.stack_array)
def clear(self):
''' clear whole array '''
self.stack_array = []
import unittest
from stack import Stack
from main import eval_postfix as epf
from main import in2post as i2p
from main import main as mn
import io
import sys
class TestEvaluation(unittest.TestCase):
def test_bad_postfix(self):
self.assertRaises(SyntaxError, epf, " 7 9 * 7 + 5 6 * - 3 + 4 -+")
self.assertRaises(ValueError, epf, [None])
class TestIn2Postfix(unittest.TestCase):
def test_infix_14(self):
postfix = i2p("7*9+7-5*6+3-4")
self.assertEqual(postfix.replace(" ", ""), "7 9 * 7 + 5 6 * - 3 + 4 -".replace(" ", ""))
def test_infix_bad_expression(self):
self.assertRaises(SyntaxError, i2p, "(8+3)*(5-6))")
class TestMainOutput(unittest.TestCase):
def test_main_output(self):
self.maxDiff = None
captured_output = io.StringIO()
sys.stdout = captured_output
mn()
sys.stdout = sys.__stdout__
data = "".join(captured_output.getvalue().split())
print(sys.stdout)
data1 = "infix: 4postfix: 4answer: 4.0infix: 5 +7postfix: 5 7 +answer: 12.0infix: 7*5postfix: 7 5 *answer: 35.0infix: (5-3)postfix: 5 3 -answer: 2.0infix: 5/5postfix: 5 5 /answer: 1.0infix: 8*5+3postfix: 8 5 * 3 +answer: 43.0infix: 8*(5+3)postfix: 8 5 3 + *answer: 64.0infix: 8+3*5-7postfix: 8 3 5 * + 7 -answer: 16.0infix: (8+3)*(5-6)postfix: 8 3 + 5 6 - *answer: -11.0infix: ((8+3)*(2-7))postfix: 8 3 + 2 7 - *answer: -55.0infix: ((8+3)*2)-7postfix: 8 3 + 2 * 7 -answer: 15.0infix: (8*5)+((3-2)-7*3)postfix: 8 5 * 3 2 - 7 3 * - +answer: 20.0infix: ((8*5+3)-7)-(5*3)postfix: 8 5 * 3 + 7 - 5 3 * -answer: 21.0infix: 7*9+7-5*6+3-4postfix: 7 9 * 7 + 5 6 * - 3 + 4 -answer: 39.0".replace(" ","")
self.assertEqual(data, data1)

The problem is in your precedence function. The rules for the Shunting yard algorithm say:
if the token is an operator, then:
while ((there is a function at the top of the operator stack)
or (there is an operator at the top of the operator stack with greater precedence)
or (the operator at the top of the operator stack has equal precedence and the token is left associative))
and (the operator at the top of the operator stack is not a left parenthesis):
pop operators from the operator stack onto the output queue.
push it onto the operator stack.
Addition and subtraction (+ and -) have equal precedence, and multiplication and division (* and /) have equal precedence. But your precedence function gives + higher precedence than -, and * higher than /. That will give the wrong output.
For example, if you're given the infix expression 7-3+4, then after parsing the 3, your output is 7 3, and the stack contains -. You parse the + and you see that + has higher precedence than -, so you push it onto the operator stack. Then you parse 4 and end up with output of 7 3 4. Finally, you start popping the stack, ending up with 7 3 4 + 1. Which will evaluate as 7 - (3 + 4).
You have to change your precedence function so that - and + have the same precedence. And * and / have the same precedence.

Related

What is the point of including print() at the end of a Python function?

def display_list(self):
if self.start is None:
print("List is empty!")
print("List is: ")
p = self.start
while p is not None:
print(p.info, " ", end=" ")
p = p.next
print()
This code simply prints the list's contents. As you can see, there is a print() function at the end of the function with no arguments. What is the point of including that, and is it actually needed?
To make the next print statement after the function starts from the next line. Compare these codes:
def fn():
i = 0
while i < 10:
print(i, end=' ')
i += 1
fn()
print('hello world')
output:
0 1 2 3 4 5 6 7 8 9 hello world
and this:
def fn():
i = 0
while i < 10:
print(i, end=' ')
i += 1
print()
fn()
print('hello world')
output:
0 1 2 3 4 5 6 7 8 9
hello world
x = 5
print(x,end="\n",sep=" ")
The end attribute of print functions which is by default set to newline is responsible for adding new line after print statement is over.You can change this to achieve any other functionality.
print("a",end="<=>",sep=" ")//outputs a<=>

How to find the first odd digit in an integer recursively

I am new to python and am trying to get more comfortable with recursion. I am trying to find the first odd digit of a integer recursively. If there are no odd digits found return -1. Whenever I run this code I always get 35 instead of just 5.
This is what I have tried
def first_odd(n):
if n == 0:
return 0
elif n % 2 == 1:
return first_odd(n//10) * 10 + n%10
else:
return first_odd(n//10)
print(first_odd(2345))
If I understand your recent comment to Tarik correctly, it sounds like you want a function that will return the first odd digit scanning an integer right to left and if no odd digits are found then return -1. For example, in your original post you stated that with the integer 2345 you expected the value of 3, but based on your comment it sounds like 5 would be the correct answer scanning right to left, right? If so, then the following code should meet that description.
from random import randint
def find_rightmost_odd_digit(number):
while number:
rightmost_digit = number % 10
if rightmost_digit % 2:
return rightmost_digit
number = number // 10
return -1
for _ in range(10):
number = randint(0, 1000)
print(f"{number:>10}{find_rightmost_odd_digit(number):>4}")
Output:
387 7
88 -1
639 9
196 9
986 9
232 3
82 -1
907 7
948 9
214 1
You were basically on the correct track but just included an extra recursion you didn't need. Consider:
def first_odd(n):
if n == 0:
return -1
if n % 2 == 1: # number is odd, return last digit
return n % 10
return first_odd(n // 10)
If this works as intended, then I might implement it as follows to combine a couple of the divisions:
def first_odd(n):
if n == 0:
return -1
quotient, remainder = divmod(n, 10)
if remainder % 2 == 1: # remainder is odd, return it
return remainder
return first_odd(quotient)
Is there also a way to find the first odd digit from left to right
using 1 parameter?
from math import log10
def first_left_odd(n):
if n == 0:
return -1
power = 10 ** int(log10(n))
digit = n // power
if digit % 2 == 1:
return digit
return first_left_odd(n - digit * power)
Or if using the math library and/or log10() is an issue, then:
def first_left_odd(n):
if n < 10:
return n if n % 2 == 1 else -1
result = first_left_odd(n // 10)
if result != -1:
return result
return first_left_odd(n % 10)
Building complex programs is a matter of combining several simple programs. For this problem I would write a program that breaks a number into digits, and one that checks if any particular number is_odd -
def first_odd(n):
for d in digits(n):
if is_odd(d):
return d
return None
We can write digits and is_odd easily -
def is_odd(n):
return n & 1
def digits(n):
if n < 0:
yield from digits(n * -1)
elif n < 10:
yield n
else:
yield from digits(n // 10)
yield n % 10
print(first_odd(2345)) # 3
print(first_odd(6804721)) # 7
print(first_odd(2468)) # 9
print(first_odd(-465321)) # 5
This might do it:
def first_odd(n, digit):
if n == 0:
return None
elif n % 2 == 1:
return digit
else:
return first_odd(n//10, digit+1)
first_odd(2345, 0)
If you want the first digit to be 1, pass 1 instead of 0
Ok, this is for left to right:
def first_odd(n, digit):
if n == 0:
return None
pos = first_odd(n//10, digit+1)
if pos is None and n % 2 == 1:
return digit
else:
return pos

FIND THE PERFECT NUMBER IN PYTHON

I do have an answer already but I'm curious if there's a better method on coding this problem through python. Thank you.
A number is called a perfect number if it is equal to the sum of all of its divisors, not including
the number itself. For instance, 6 is a perfect number because the divisors of 6 are 1, 2, 3, 6
and 6 = 1 + 2 + 3. As another example, 28 is a perfect number because its divisors are 1, 2, 4,
7, 14, 28 and 28 = 1 + 2 + 4 + 7 + 14. However, 15 is not a perfect number because its divisors
are 1, 3, 5, 15 and 15 6= 1 + 3 + 5. Write a program that finds all four of the perfect numbers
that are less than 10000.
Here is my answer.
for i in range(1,10000):
summ = 0
for m in range(i):
if i % (m+1) == 0:
summ = summ + (m+1)
g = summ - i
if g == i :
print(g)
Here is perfect number algorithm that checks for perfect numbers using the Lucas Lehmer Test:
def ffs(x):
return (x&-x).bit_length()-1
def levelx(N, withstats=False):
if N <= 1: return False
temp = N
newlevel = temp.bit_length()
primetest = temp//(2**(ffs(temp)))
offset = temp//primetest
s = 4
nextlevel = newlevel // 2
check = temp // (2**nextlevel)
prevtemp = 2**nextlevel
if withstats == True:
print (newlevel, newlevel, temp)
print (newlevel, nextlevel+one, prevtemp)
if (prevtemp & (prevtemp-1) == 0) and prevtemp != 0:
if offset.bit_length() == primetest.bit_length():
if ((primetest+1) & ((primetest+1)-1) == 0):
for x in range(primetest.bit_length()-1):
s = (s * s - 2) % primetest
if withstats == True:
print(s)
if s in [0,2]: return True
return False
else: return False
else: return False
else: return False
Here is the output:
In [645]: for x in range(2,100):
...: if levelx((2**(x-1))*(2**x-1)) == True:
...: print(x, (2**(x-1))*(2**x-1))
...:
...:
2 6
3 28
5 496
7 8128
13 33550336
17 8589869056
19 137438691328
31 2305843008139952128
61 2658455991569831744654692615953842176
89 191561942608236107294793378084303638130997321548169216
You can use gmpy2 to speed these up by about 10x.
for j in range(1,10000):
sum=0
for I in range(1,J):
if J%I==0:
sum= sum + I
if j==sum:
print(J," is a perfect square")

Create a function that computes the approximation of pi, based on the number of iterations specified

hint:pi can be computed by 4*(1-1/3+1/5-1/7+1/9- ...).
I have idea to solve this question by using while loop, but I'm confused that, in while loop, how can I save my variable every time when i use if conditional.
Here is my code.
def piA(num):
i = 1
pi = 4
while i <= num:
s = 0
float(s)
if i % 2 == 1:
s = s + (1/(2*i-1))
print(s)
elif i % 2 == 0:
s = s - (1/(2*i-1))
print(s)
i += 1
print(s)
return pi*s
print(piA(2))
The result shows:
1.0
1.0
-0.3333333333333333
-0.3333333333333333
-1.3333333333333333
You don't have to save the previous variable, just use builtin method sum():
def pi(num):
return 4*sum((1 if i % 2 else -1)*(1 / (2*i - 1)) for i in range(1, num+1))
print(pi(10000))
Prints:
3.1414926535900345

24 game using Python3

24 is a mental arithmetic game, first played using poker cards. Given four integers, the objective is to produce the number 24 using the standard arithmetic operators +, −, ∗ and /, while consuming all four numbers in the process.
For example, given the numbers { 2, 3, 5, 6 }, one could do . . .
2 * 3 = 6 , 5 * 6 = 30 , 30 - 6 = 24 and so on
Note: The given numbers can be used in any order to produce 24.
Write a program that takes in four integers, and determines whether it is possible to reach 24 from those numbers. You can assume the number 0 will not form part of the input.
I am not sure how to let the function run my 4 inputs
import itertools
ints = input('Enter 4 integers: ').split()
n1=int(ints[0])
n2=int(ints[1])
n3=int(ints[2])
n4=int(ints[4])
def with_brackets(lst, ops_lst):
for op in ops_lst: #calculate when no brackets
expr1 = '('+lst[0]+op[0]+lst[1]+')'+op[1]+lst[2]+op[2]+lst[3]
expr2 = '('+lst[0]+op[0]+lst[1]+op[1]+lst[2]+')'+op[2]+lst[3]
expr3 = lst[0]+op[0]+'('+lst[1]+op[1]+lst[2]+')'+op[2]+lst[3]
expr4 = '('+lst[0]+op[0]+lst[1]+')'+op[1]+'('+lst[2]+op[2]+lst[3]+')'
for expr in [expr1, expr2, expr3, expr4]:
try:
t=eval(expr)
except: #except zerodivision error
pass
if abs(t-24) < 0.001:
return expr
return 0
#return 4 numbers to calculate 24
def hasMethod(numbers, ops_lst):
for lst in itertools.permutations(numbers):
lst = list(map(lambda x:str(x), lst))
#without brackets
for op in ops_lst:
expr = lst[0]+op[0]+lst[1]+op[1]+lst[2]+op[2]+lst[3]
if abs(eval(expr)-24) < 0.001:
return expr
#with brackets
expr = with_brackets(lst, ops_lst)
if expr != 0:
return expr
return 0
#method of return 4 numbers to calculate 24,no way return"No Method"
def cal_24(numbers):
ops = ['+','-','*','/']
ops_lst = [[i,j,k] for i in ops for j in ops for k in ops]
expr = hasMethod(numbers, ops_lst)
if expr != 0:
return expr
else:
return 'No method!'
#ways to calculate 24 at all situaions
def main():
numbers_lst = [[i,j,k,l] for i in range(1,14) for j in range(1,14)\
for k in range(1,14) for l in range(1,14)]
for numbers in numbers_lst:
a = list(map(lambda x: str(x), numbers))
methodInfo = "[%s,%s,%s,%s]: %s\n"%(a[0],a[1],a[2],a[3],cal_24(numbers))
print(methodInfo)
main()
Expected results:
Example 1:
Enter 4 integers: 2 3 5 6
Yes! 24 is reachable from { 2, 3, 5, 6 }
Example 2:
Enter 4 integers: 1 1 1 1
Noooo :( 24 is unreachable from { 1, 1, 1, 1 }
Example 3:
Enter 4 integers: hello
Input must consist of 4 integers
This question is very interesting.
from __future__ import division, print_function
import random, ast, re
import sys
if sys.version_info[0] < 3: input = raw_input
def choose4():
'four random digits >0 as characters'
return [str(random.randint(1,9)) for i in range(4)]
def welcome(digits):
print (__doc__)
print ("Your four digits: " + ' '.join(digits))
def check(answer, digits):
allowed = set('() +-*/\t'+''.join(digits))
ok = all(ch in allowed for ch in answer) and \
all(digits.count(dig) == answer.count(dig) for dig in set(digits)) \
and not re.search('\d\d', answer)
if ok:
try:
ast.parse(answer)
except:
ok = False
return ok
def main():
digits = choose4()
welcome(digits)
trial = 0
answer = ''
chk = ans = False
while not (chk and ans == 24):
trial +=1
answer = input("Expression %i: " % trial)
chk = check(answer, digits)
if answer.lower() == 'q':
break
if answer == '!':
digits = choose4()
print ("New digits:", ' '.join(digits))
continue
if not chk:
print ("The input '%s' was wonky!" % answer)
else:
ans = eval(answer)
print (" = ", ans)
if ans == 24:
print ("Thats right!")
print ("Thank you and goodbye")
if __name__ == '__main__': main()

Resources