Python Forum
Evaluating arithmetic expression with recursion. - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Evaluating arithmetic expression with recursion. (/thread-35804.html)



Evaluating arithmetic expression with recursion. - muddybucket - Dec-16-2021

Hi, I am tasked to make a recursive function which evaluates the expression starting from the given position. Return the value and the first position after the read sub-expression. If the string starting at the given expression is not an arithmetic expression, return None. To avoid divisions by zero we do not allow division in arithmetic expressions.
  • If a is a number, then evaluate(a) is that number.
  • If a and b are arithmetic expressions, then evaluate((a+b)) = evaluate(a)+evaluate(b), evaluate((a-b)) = evaluate(a)-evaluate(b), and evaluate((a*b)) = evaluate(a)*evaluate(b).

def read_positive_integer(text, position):
    text_mod = text[position:]
    if not (text[position]).isdigit():
        return None
    try:
        return (int(text_mod), len(text_mod) + position )
    except:
        return read_positive_integer(text[:-1], position)

def evaluate(expression, position):
    r = read_positive_integer(expression, position)
    if r != None:
        return r

    else:
        if expression[position] == "(":
            a,pos = evaluate(expression, position+1)
            operator = expression[pos]
            b,pos = evaluate(expression, pos+1)
            op_dict = {"+":a+b, "-":a-b, "*":a*b}

            if expression[pos] == ")":
                return op_dict[operator] 
I have tried giving it the following input:
evaluate("((1-1)+(2*1))", 0)
But it outputs this error:
Error:
cannot unpack non-iterable int object
PD: The function read_positive_integer has no flaws and it works as it should (it got accepted by the auto-corrector)


RE: Evaluating arithmetic expression with recursion. - BashBedlam - Dec-16-2021

On line 17a,pos =is looking for two return values andevaluate () is only returning one. This is the source of the error that you are getting.


RE: Evaluating arithmetic expression with recursion. - supuflounder - Dec-16-2021

(Dec-16-2021, 01:40 PM)muddybucket Wrote: Hi, I am tasked to make a recursive function which evaluates the expression starting from the given position. Return the value and the first position after the read sub-expression. If the string starting at the given expression is not an arithmetic expression, return None. To avoid divisions by zero we do not allow division in arithmetic expressions.
  • If a is a number, then evaluate(a) is that number.
  • If a and b are arithmetic expressions, then evaluate((a+b)) = evaluate(a)+evaluate(b), evaluate((a-b)) = evaluate(a)-evaluate(b), and evaluate((a*b)) = evaluate(a)*evaluate(b).

def read_positive_integer(text, position):
    text_mod = text[position:]
    if not (text[position]).isdigit():
        return None
    try:
        return (int(text_mod), len(text_mod) + position )
    except:
        return read_positive_integer(text[:-1], position)

def evaluate(expression, position):
    r = read_positive_integer(expression, position)
    if r != None:
        return r

    else:
        if expression[position] == "(":
            a,pos = evaluate(expression, position+1)
            operator = expression[pos]
            b,pos = evaluate(expression, pos+1)
            op_dict = {"+":a+b, "-":a-b, "*":a*b}

            if expression[pos] == ")":
                return op_dict[operator] 
I have tried giving it the following input:
evaluate("((1-1)+(2*1))", 0)
But it outputs this error:
Error:
cannot unpack non-iterable int object
PD: The function read_positive_integer has no flaws and it works as it should (it got accepted by the auto-corrector)

The error occurred on some line. Without knowing what line that is, it is hard to guess.


RE: Evaluating arithmetic expression with recursion. - deanhystad - Dec-17-2021

Your error occurs when this code executes:
            if expression[pos] == ")":
                return op_dict[operator] 
This is seen if you print out the value(s) returned by evaluate()
def read_positive_integer(text, position):
    text_mod = text[position:]
    if not (text[position]).isdigit():
        return None
    try:
        return (int(text_mod), len(text_mod) + position )
    except:
        return read_positive_integer(text[:-1], position)
 
def evaluate(expression, position):
    r = read_positive_integer(expression, position)
    if r != None:
        return r
 
    else:
        if expression[position] == "(":
            results = evaluate(expression, position+1)
            print("A", results)
            a = results[0]
            pos = results[1]
            operator = expression[pos]
            results = evaluate(expression, pos+1)
            print("B", results)
            b = results[0]
            pos = results[1]
            op_dict = {"+":a+b, "-":a-b, "*":a*b}
 
            if expression[pos] == ")":
                print("C", op_dict[operator])
                return op_dict[operator]
                
evaluate("((1-1)+(2*1))", 0)
Output:
A (1, 3) B (1, 5) C 0 A 0
When you execute the operator you are only returning the result and not a position. This raises a type error when the return value is unpacked.

Changing your code to return a position for every condition fixes the error.
def read_positive_integer(text, position):
    text_mod = text[position:]
    if not (text[position]).isdigit():
        return None
    try:
        return (int(text_mod), len(text_mod) + position )
    except:
        return read_positive_integer(text[:-1], position)
 
def evaluate(expression, position):
    r = read_positive_integer(expression, position)
    if r != None:
        return r
 
    else:
        if expression[position] == "(":
            a, pos = evaluate(expression, position+1)
            operator = expression[pos]
            b, pos = evaluate(expression, pos+1)
            op_dict = {"+":a+b, "-":a-b, "*":a*b}
 
            if expression[pos] == ")":
                print("C", op_dict[operator])
                return op_dict[operator], pos

evaluate("((1-1)+(2*1))", 0)
And gets you to the next error.