Missing Operators Calculator In Python

Question:

I’m trying to write a program to find all the results of a mathematical expression and 4 missing operators which are +,*,- and /. for example all the results for 2?3 will be something like this:

(2+3) = 5
(2-3) = -1
(2*3) = 6
(2/3) = 0.6666666666666666 

These are my codes

import itertools

expression='1?2?3'

def operation_counter(expression):
    count = 0
    for i in expression:
        if (i == '?'):
            count += 1
        else:
            pass
    return count

def parenthesize(expression):
    operators = ['?']
    depth = len([s for s in expression if s in operators]) 
    if depth == 0:
        return [expression]
    if depth== 1:
        return ['('+ expression + ')']
    answer = []
    for index, symbol in enumerate(expression):
        if symbol in operators:
            left = expression[:index]
            right = expression[(index+1):]
            expressions = ['(' + lt + ')' + symbol +'(' + rt + ')' 
                           for lt in parenthesize(left) 
                           for rt in parenthesize(right) ]
            answer.extend(expressions)
    return answer 

def operation_replacer(expression):
    spare = expression
    opr = ['+', '-', '*', '/']
    operation_numbers = operation_counter(expression)
    products = list(itertools.product(opr, repeat=operation_numbers))
    for i in products:
        pair_of_operators = str(i)

        length = len(pair_of_operators)
        z = []
        for i in range(0,length):
            s = pair_of_operators.find("'",i,length)
            e = pair_of_operators.find("'",s+1,length)
            x = pair_of_operators[s+1:e]
            if (x != ""):
                pair_of_operators = pair_of_operators[e:length]
                z.append(x)
        
        for i in z:
            expression = expression.replace('?',i,1)
        
        
        try:
            evaluation = str(eval(expression))
        except ZeroDivisionError:
            evaluation = 'Division By Zero!'
        
        print(expression + ' = ' + evaluation)
        expression = spare
        
        
for i in parenthesize(expression):
    result = operation_replacer(i)
    print(result)

The problem is that the program works correctly for five numbers and less like: 1?2?3?4?5 but I get an error when I apply it to more complex expressions more than five numbers like: 3?6?1?5?12?6. I tried a lot but never found the solution to this issue

This is the full traceback message:

Traceback (most recent call last):

  File "C:UsersMuhammadAppDataLocalPackagesPythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0LocalCachelocal-packagesPython38site-packagesIPythoncoreinteractiveshell.py", line 3417, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)

  File "<ipython-input-14-790301a5c9b0>", line 64, in <module>
    result = operation_replacer(i)

  File "<ipython-input-14-790301a5c9b0>", line 55, in operation_replacer
    evaluation = str(eval(expression))

  File "<string>", line 1
    (1)+((2)+((3)+((4)+((5?6)))))
                          ^
SyntaxError: invalid syntax

The expected output to 6 and more numbers is too long and I can’t write all the possibilities since it exceeds the maximum characters allowed in this question

Also, I get a None value in the results and i don’t know where is that coming from, for example see this result for 1?2?3

(1)+((2+3)) = 6
(1)+((2-3)) = 0
(1)+((2*3)) = 7
(1)+((2/3)) = 1.6666666666666665
(1)-((2+3)) = -4
(1)-((2-3)) = 2
(1)-((2*3)) = -5
(1)-((2/3)) = 0.33333333333333337
(1)*((2+3)) = 5
(1)*((2-3)) = -1
(1)*((2*3)) = 6
(1)*((2/3)) = 0.6666666666666666
(1)/((2+3)) = 0.2
(1)/((2-3)) = -1.0
(1)/((2*3)) = 0.16666666666666666
(1)/((2/3)) = 1.5
None
((1+2))+(3) = 6
((1+2))-(3) = 0
((1+2))*(3) = 9
((1+2))/(3) = 1.0
((1-2))+(3) = 2
((1-2))-(3) = -4
((1-2))*(3) = -3
((1-2))/(3) = -0.3333333333333333
((1*2))+(3) = 5
((1*2))-(3) = -1
((1*2))*(3) = 6
((1*2))/(3) = 0.6666666666666666
((1/2))+(3) = 3.5
((1/2))-(3) = -2.5
((1/2))*(3) = 1.5
((1/2))/(3) = 0.16666666666666666
None
Asked By: Muhammad

||

Answers:

  1. First the easy one – None issue. You get None because the operation_replacer function does not return anything and that result you’re printing in the loop at the end.

  2. This parser works works only for <5 values because there is a bit clumsy piece of code – preparing operation in the pair_operators loop. I really don’t get it – from a tuple you get (the operators product) you stringify it and then parse it only to get list… You may use tuple without that entire parsing thing.

Example without paarsing

def operation_replacer(expression):                                                                                     
    spare = expression                                                                                                  
    ops = ['+', '-', '*', '/']                                                                                          
    ops_count = len([ch in ch in experssion if ch == '?'])                                                              
    products = list(itertools.product(ops, repeat=ops_count))                                                           
    for op_set in products:                                                                                             
        for op in op_set:                                                                                               
            expression = expression.replace('?', op, 1)                                                                 
        try:                                                                                                            
            evaluation = str(eval(expression))                                                                          
        except ZeroDivisionError:                                                                                       
            evaluation = 'Division By Zero!'                                                                            

        print(expression + ' = ' + evaluation)                                                                             
        expression = spare                                                                                              
Answered By: kwarunek

Not a real answer, but the code is too big to post as a comment. You can shorter a lot your code with the split built-in function. You will find below a working example with 6 numbers (without parenthesis). I guess the below code can be optimized a little more by using itertools:

import itertools

expression='1?2?3?4?5?6'
opr = ['+', '-', '*', '/']
sp = expression.split('?')
products = list(itertools.product(opr, repeat=len(sp)-1))

for product in products:
    expression = [ sp[i]+product[i] for i in range(0,len(product))]
    expression.append(sp[len(sp)-1])
    expression = ''.join(expression)
    print(expression)
Answered By: pyOliv

I have rewritten the code and changed a lot of things, the code may not be perfect but it does the job

import itertools

string='1?2?3'

def operation_counter(string):
    count = 0
    for i in string:
        if (i == '?'):
            count += 1
        else:
            pass
    return count

def q_positions(string):
    positions = []
    for i in range(len(string)):
        if (string[i] == '?'):
            positions.append(i)
    return positions

def string_char_replacer(string,newstring,index):
    string = string[:index] + newstring + string[index + 1:]
    return string

def parenthesize(string):
    operators = ['?']
    depth = len([s for s in string if s in operators])
    if depth == 0:
        return [string]
    if depth== 1:
        return ['('+ string + ')']
    answer = []
    for index, symbol in enumerate(string):
        if symbol in operators:
            left = string[:index]
            right = string[(index+1):]
            strings = ['(' + lt + ')' + symbol +'(' + rt + ')'
                           for lt in parenthesize(left)
                           for rt in parenthesize(right) ]
            answer.extend(strings)
    return answer

def operation_replacer(string):
    opr = ['+', '-', '*', '/']
    operation_numbers = operation_counter(string)
    products = list(itertools.product(opr, repeat=operation_numbers))
    #print(products)
    return products


def single_operation_list(string):
    single_operators = []
    for i in range(len(string)):
        char = string[i]
        if (char == "'" and string[i+1] != "," and  string[i+1] != ")"):
            single_operator = string[i+1:i+2]
            single_operators.append(single_operator)
    return single_operators

exp= parenthesize(string)
opr_tuple = operation_replacer(string)

opr = []
for i in opr_tuple:
    tuple = str(i).replace(' ', '')
    opr.append(tuple)


for i in exp:
    for j in opr:
        h = single_operation_list(j)
        spare = i
        for l in h:
            i = i.replace('?',l,1)
            find_q = i.find('?')
            if (find_q == -1):
                try:
                    evaluation = str(eval(i))
                except ZeroDivisionError:
                    evaluation = 'Division By Zero!'
                print(i + ' = ' + evaluation)
            else:
                pass
        i = spare
Answered By: Muhammad
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.