Michael Houston
Michael Houston

Reputation: 11

Replace values in dict if value of another key within a nested dict is found in value

I have the following nested dict:

 ex_dict = {'path1':
             {'$variable1': '2018-01-01',
              '$variable2': '2020-01-01',
              '$variable3': '$variable1',
              '$variable4': '$variable3'},
            'path2':
             {'$variable1': '2018-01-01',
              '$variable2': '2020-01-01',
              '$variable3': '$variable1',
              '$variable4': '$variable1 + $variable2'}
           }

I want to replace any $variableX specified for a dict key with the dict value from another key if the key from the other dict value if found in the value of the original dict key. See example output below:

{'path1':
         {'$variable1': '2018-01-01',
          '$variable2': '2020-01-01',
          '$variable3': '2018-01-01',  # Substituted with value from key:variable1
          '$variable4': '2018-01-01'}, # Substituted with value from key:variable3 (after variable3 was substituted with variable1)    
 'path2':
         {'$variable1': '2018-01-01',
          '$variable2': '2020-01-01',
          '$variable3': '2018-01-01',  # Substituted with value from key:variable1
          '$variable4': '2018-01-01 + 2020-01-01'} # Substituted with value from key:variable3 (after variable3 was substituted with variable1) and key:variable2
       }  

Does anyone have any suggestions?

Upvotes: 1

Views: 92

Answers (3)

Keyur Potdar
Keyur Potdar

Reputation: 7238

Not a very Pythonic solution, but, does the trick:

ex_dict = {'path1':
               {'$variable1': '2018-01-01',
                '$variable2': '2020-01-01',
                '$variable3': '$variable1',
                '$variable4': '$variable3'},
           'path2':
               {'$variable1': '2018-01-01',
                '$variable2': '2020-01-01',
                '$variable3': '$variable1',
                '$variable4': '$variable1 + $variable2'}
           }

for path, d in ex_dict.items():
    for k, v in d.items():
        if v.startswith('$variable'):
            try:
                if '+' in v:
                    ex_dict[path][k] = ' + '.join(ex_dict[path][x.strip()] for x in v.split('+'))
                else:
                    ex_dict[path][k] = ex_dict[path][v]
            except KeyError:
                pass

pprint(ex_dict)

Output:

{'path1': {'$variable1': '2018-01-01',
           '$variable2': '2020-01-01',
           '$variable3': '2018-01-01',
           '$variable4': '2018-01-01'},
 'path2': {'$variable1': '2018-01-01',
           '$variable2': '2020-01-01',
           '$variable3': '2018-01-01',
           '$variable4': '2018-01-01 + 2020-01-01'}}

Upvotes: 1

Ajax1234
Ajax1234

Reputation: 71451

You can use a dictionary comprehension:

import re
dict = {'path1':
     {'$variable1': '2018-01-01',
      '$variable2': '2020-01-01',
      '$variable3': '$variable1',
      '$variable4': '$variable3'},
    'path2':
     {'$variable1': '2018-01-01',
      '$variable2': '2020-01-01',
      '$variable3': '$variable1',
      '$variable4': '$variable1 + $variable2'}
   }

final_data = {a:{c:d if re.findall('\d+-\d+-\d+', d) else \
re.sub('\$\w+', '{}', d).format(*[b[i] for i in re.findall('\$\w+', d)]) \
 for c, d in b.items()} for a, b in dict.items()}

Output:

{'path2': {'$variable4': '2018-01-01 + 2020-01-01', '$variable2': '2020-01-01', '$variable3': '2018-01-01', '$variable1': '2018-01-01'}, 'path1': {'$variable4': '$variable1', '$variable2': '2020-01-01', '$variable3': '2018-01-01', '$variable1': '2018-01-01'}}

Upvotes: 0

Brendan Abel
Brendan Abel

Reputation: 37509

You could do replacement by recursively walking through the dict and using the re library to do the replacements

import re

def process_dict(d):
    reprocess = []
    keys = d.keys()
    while keys:
        for k in keys:
            v = d[k]
            if isinstance(v, dict):
                process_dict(v)
            elif '$' in v:
                d[k] = re.sub(r'\$\w+', lambda m: d[m.group(0)] if m.group(0) in d else m.group(0), v)
                if '$' in d[k] and d[k] != v:
                    reprocess.append(k)
        keys = reprocess
        reprocess = []

Edit:

I added a reprocessing step to handle the cases where the references are chained and require multiple passes through some keys in the dictionary to fully process them.

Upvotes: 2

Related Questions