PepperoniPizza PepperoniPizza - 1 month ago 5
Python Question

Python modify dictionary recursively

I have a Python AST parser that converts expressions like

1==1 or 2==2 or 3==3
into this dictionary:

{ 'args': [ {'args': [{'value': 1}, {'value': 1}], 'function': '=='},
{'args': [{'value': 2}, {'value': 2}], 'function': '=='},
{'args': [{'value': 3}, {'value': 3}], 'function': '=='}],
'function': 'or'}


This is then converted to JSON and POSTed to and API endpoint, however the API only understands binary
or
operations. So the pasted dictionary above needs to be converted (nested) into the following:

{ 'args': [ { 'args': [ { 'args': [{'value': 1}, {'value': 1}],
'function': '=='},
{ 'args': [{'value': 2}, {'value': 2}],
'function': '=='}],
'function': 'or'},
{'args': [{'value': 3}, {'value': 3}], 'function': '=='}],
'function': 'or'}


Doing this from the Python AST is not possible because the
BoolOp
has 3 elements so I think it's best to do it recursively. However I can't visualize a correct way to achieve this iterating the dictionary in a recursive manner.

edit:

The dictionary can be deeply nested like:

{ 'args': [ {'args': [{'value': 1}, {'value': 1}], 'function': '=='},
{'args': [{'value': 2}, {'value': 2}], 'function': '=='},
{ 'args': [ { 'args': [{'value': 3}, {'value': 3}],
'function': '=='},
{ 'args': [{'value': 4}, {'value': 4}],
'function': '=='},
{ 'args': [{'value': 5}, {'value': 5}],
'function': '=='}],
'function': 'or'}],
'function': 'and'}

Answer

You could do something like this:

def _nest_ors(args):
    assert len(args) >= 2

    if len(args) == 2:
        return {
            'function': 'or',
            'args': args
        }

    return {
        'function': 'or',
        'args': [args[0], _nest_ors(args[1:])]
    }


def fix_ors(ast):
    assert ast['function'] == 'or'

    return _nest_ors(ast['args'])


expression = {'args': [{'args': [{'value': 1}, {'value': 1}], 'function': '=='},
                       {'args': [{'value': 2}, {'value': 2}], 'function': '=='},
                       {'args': [{'value': 3}, {'value': 3}], 'function': '=='}],
              'function': 'or'}

print(fix_ors(expression))

If you have really huge expressions, you will have to replace the recursion with an iterative solution.

Comments