-2

I want to write a Python program which can takes arithmetic expressions in JSON format, parses and evaluates the answer however when using Nested JSON object like the one below. It gives me the error "TypeError: unsupported operand type(s) for +: 'int' and 'list'"

{
    "root": { "description":"This is a very deeply first nested expression, and it evaluates to 12.",       
        "plus": [{
                "plus": [{
                        "plus": [{
                                "plus": [{
                                        "plus": [{
                                                "int": 2
                                            },
                                            {
                                                "int": 2
                                            }
                                        ]
                                    },
                                    {
                                        "int": 2
                                    }
                                ]
                            },
                            {
                                "int": 2
                            }
                        ]
                    },
                    {
                        "int": 2
                    }
                ]
            },
            {
                "int": 2
            }
        ]
    }
}

So far I have managed to get this from https://stackoverflow.com/questions/58170675/how-to-use-python-to-return-the-result-of-an-arithmetic-expressions-from-json.

def evaluate_expr(parsed_expr):
    val = 0
    with open("expression4.json") as complex_data:
        data = complex_data.read()
        z = json.loads(data)

    data = z['root']
    for op, val in data.items():
        if op == 'description':
            pass
        elif op == 'plus':
            return sum(element[k] for element in data[op] for k in element)
        elif op == 'minus' or op == 'times':
            if len(data[op]) != 2:
                raise ValueError('2 elements expected if operation is minus or times')
            nums = [element[k] for element in data[op] for k in element]
            if op == 'minus':
                return abs(nums[0] - nums[1])
            else:
                return nums[0] * nums[1]
        else:
            raise ValueError('Invalid operation')

How would I iterate over the above Nested JSON Object recursively to evaluate the expression.

1 Answers1

0

For this type of challenges the best way to go is to use recursion.

A recursive function is a function which calls itself at some points. To create a recursive function you should follow a 2 step rule:

  1. Create an exit condition
  2. Call the function again

in your example the data is kind of not convenient. I would change the data type but the logic would not change.

First I'm going to get ride of the root and desertion part by removing the description and pass the data left inside the root.

The data only contains the operation type (plus) and the data (int).

{'plus': [{'plus': [{'plus': [{'plus': [{'plus': [{'int': 2}, {'int': 2}]}, {'int': 2}]}, {'int': 2}]}, {'int': 2}]}, {'int': 2}]}

Now you can check if the dictionary contains plus. If it does you should call the same function again for both first and second element of the list with correct operator (in plus example it's +) in between them. Do the same thing for other operators too (minus, multiply and divide) and return the values.

Otherwise there is no operation left and you should only return the int

The code would look like:

def do_the_math(data):
    if "plus" in data:
        return do_the_math(data["plus"][0]) + do_the_math(data["plus"][1])
    elif "minus" in data:
        return do_the_math(data["minus"][0]) - do_the_math(data["minus"][1])
    elif "multiply" in data:
        return do_the_math(data["multiply"][0]) * do_the_math(data["multiply"][1])
    elif "divide" in data:
        return do_the_math(data["divide"][0]) / do_the_math(data["divide"][1])

    return data["int"]


if __name__ == '__main__':
    data = {
        "root": {"description": "This is a very deeply first nested expression, and it evaluates to 12.",
                 "plus": [{
                     "plus": [{
                         "plus": [{
                             "plus": [{
                                 "plus": [{
                                     "int": 2
                                 },
                                     {
                                         "int": 2
                                     }
                                 ]
                             },
                                 {
                                     "int": 2
                                 }
                             ]
                         },
                             {
                                 "int": 2
                             }
                         ]
                     },
                         {
                             "int": 2
                         }
                     ]
                 },
                     {
                         "int": 2
                     }
                 ]
                 }
    }
    data["root"].pop("description")
    print(do_the_math(data["root"]))

Please notice you never described if the operations must start from inside towards out of the dict or vice versa. In any case you can change the order of the operation from return do_the_math(data["plus"][0]) + do_the_math(data["plus"][1]) to return do_the_math(data["plus"][1]) + do_the_math(data["plus"][0])

Note: In this example we changed the order of our rule from:

  1. Create an exit condition
  2. Call the function again

to

  1. Create a(some) call condition(s)
  2. Exit the function

Note: Recursion in Python is not what you would want since Python is not good at it. See: Thomas Wouters's answer

MSH
  • 1,743
  • 2
  • 14
  • 22