Replace the keys of the nested dictionary with the value of another dictionary (where the keys of the two dict are equal)), the value for the key can be a list of dicts

I have two dict, dict1 and dict2, I want to build a new dict (or manipulate dict1) using key-value pairs like (dict2 value: dict1 value [where dict key and dict2 key are the same]), the key value can be a list of dicts (as you will see in the input example)

INPUT IS

dict1 = {"key1":{"key3":"value1","key2":"value2","key4":{"key5":"value3","key6":{"key7":"value4","key8":{"key9":"value5","key10":"value6","key55":"value7"}},"key11":{"key12":"value8","key13":"value9"},"key14":[{"key15":"value10","key16":"value11","key17":"value12"},{"key15":"value13","key16":"value14","key17":"value15"}]}}}

dict2 = {"key1":"ab","key2":"bc","key3":"cd","key4":"de","key5":"ef","key6":"fg","key7":"gh","key8":"hi","key9":"ij","key10":"jk","key55":"kl","key11":"lm","key12":"mn","key13":"no","key14":"op","key15":"pq","key16":"qr","key17":"qs"}

My function

def walk(dict1, dict2):
    output = {}
    for key, value in dict1.iteritems():

        if isinstance(value, dict):
            output[dict2[key]] = walk(value, dict2)
        elif isinstance(value, list):
            output[dict2[key]] = walk_list(value, dict2)
        else:
            output[dict2[key]] = value
    return output

def walk_list(sublist, dict2):
    output = []
    for i in sublist:

        if isinstance(i, dict):
            output = walk(i, dict2)
        elif isinstance(value, list):
            output = walk_list(i, dict2)
        else:
            output.append((key, value))
    return output

output = walk(dict1, dict2)
output = json.dumps(output)
print output

EXIT AM AM

 {"ab": {"de": {"lm": {"mn": "value8", "no": "value9"}, "ef": "value3", "fg": {"hi": {"ij": "value5", "jk": "value6", "kl": "value7"}, "gh": "value4"}, "op": {"pq": "value13", "qs": "value15", "qr": "value14"}}, "bc": "value2", "cd": "value1"}}

EXPECTED OUTPUT IS

 {"ab":{"cd":"value1","bc":"value2","de":{"ef":"value3","fg":{"gh":"value4","hi":{"ij":"value5","jk":"value6","kl":"value7"}},"lm":{"mn":"value8","no":"value9"},"op":[{"pq":"value10","qr":"value11","qs":"value12"},{"pq":"value13","qr":"value14","qs":"value15"}]}}}

Please correct my code.

+4
source share
3 answers

A very simple solution that performs a recursive step very early and, as such, has a very simple logic:

def translateKeys (obj, keyNames):
    if isinstance(obj, dict):
        return {keyNames.get(k, k): translateKeys(v, keyNames) for k, v in obj.items()}
    elif isinstance(obj, list):
        return [translateKeys(v, keyNames) for v in obj]
    else:
        return obj

, , - (, - ) , . obj .

:

>>> dict1 = {"key1":{"key3":"value1","key2":"value2","key4":{"key5":"value3","key6":{"key7":"value4","key8":{"key9":"value5","key10":"value6","key55":"value7"}},"key11":{"key12":"value8","key13":"value9"},"key14":[{"key15":"value10","key16":"value11","key17":"value12"},{"key15":"value13","key16":"value14","key17":"value15"}]}}}
>>> dict2 = {"key1":"ab","key2":"bc","key3":"cd","key4":"de","key5":"ef","key6":"fg","key7":"gh","key8":"hi","key9":"ij","key10":"jk","key55":"kl","key11":"lm","key12":"mn","key13":"no","key14":"op","key15":"pq","key16":"qr","key17":"qs"}
>>> expected =  {"ab":{"cd":"value1","bc":"value2","de":{"ef":"value3","fg":{"gh":"value4","hi":{"ij":"value5","jk":"value6","kl":"value7"}},"lm":{"mn":"value8","no":"value9"},"op":[{"pq":"value10","qr":"value11","qs":"value12"},{"pq":"value13","qr":"value14","qs":"value15"}]}}}
>>> result = translateKeys(dict1, dict2)
>>> result
{'ab': {'de': {'fg': {'gh': 'value4', 'hi': {'ij': 'value5', 'jk': 'value6', 'kl': 'value7'}}, 'op': [{'qr': 'value11', 'pq': 'value10', 'qs': 'value12'}, {'qr': 'value14', 'pq': 'value13', 'qs': 'value15'}], 'ef': 'value3', 'lm': {'no': 'value9', 'mn': 'value8'}}, 'cd': 'value1', 'bc': 'value2'}}
>>> result == expected
True

, keyNames :

>>> result = translateKeys(dict1, dict2)
>>> invertedKeyNames = {v: k for k, v in dict2.items()}
>>> original = translateKeys(result, invertedKeyNames)
>>> original == dict1
True
+3

, ,

def walk(dict1, dict2):
    res = dict()
    for k,v in dict1.items():
        if isinstance(v,list):
            newv = [walk(x, dict2) for x in v]
        elif isinstance(v,dict):
            newv = walk(v, dict2)
        else:
            newv = v
        res[dict2.get(k, k)] = newv # keep the same key if not present in dict2
    return res

expected = {"ab":{"cd":"value1","bc":"value2","de":{"ef":"value3","fg":{"gh":"value4","hi":{"ij":"value5","jk":"value6","kl":"value7"}},"lm":{"mn":"value8","no":"value9"},"op":[{"pq":"value10","qr":"value11","qs":"value12"},{"pq":"value13","qr":"value14","qs":"value15"}]}}}

output = walk(dict1, dict2)
print(output)
print(output == expected)

{'ab': {'de': {'lm': {'no': 'value9', 'mn': 'value8'}, 'ef': 'value3', 'fg': {'hi': {'ij': 'value5', 'kl': 'value7', 'jk': 'value6'}, 'gh': 'value4'}, 'op': [{'qr': 'value11', 'qs': 'value12', 'pq': 'value10'}, {'qr': 'value14', 'qs': 'value15', 'pq': 'value13'}]}, 'cd': 'value1', 'bc': 'value2'}}
True

:

  • ,
  • ,
  • ,

EDIT:

, json (, list, dict, value),

def walk(obj, keys):
    if isinstance(obj,list):
        return [walk(x, keys) for x in obj]
    elif isinstance(obj,dict):
        return {keys.get(k, k): walk(v, keys) for k,v in obj.items()}
    else:
        return obj

, @Poke , .

EDIT2:

dict1, (.. dict2 bijective),

back2dict1 = walk(output, {v:k for k,v in dict2.items()})
print(back2dict1)
print(back2dict1 == dict1)

{'key1': {'key3': 'value1', 'key2': 'value2', 'key4': {'key5': 'value3', 'key11': {'key12': 'value8', 'key13': 'value9'}, 'key14': [{'key15': 'value10', 'key16': 'value11', 'key17': 'value12'}, {'key15': 'value13', 'key16': 'value14', 'key17': 'value15'}], 'key6': {'key7': 'value4', 'key8': {'key10': 'value6', 'key55': 'value7', 'key9': 'value5'}}}}}
True
+1

I think this is due to your walk_list function with the assigned output variable, not the addition. This is my version:

dict1 = {"key1":{"key3":"value1","key2":"value2","key4":{"key5":"value3","key6":{"key7":"value4","key8":{"key9":"value5","key10":"value6","key55":"value7"}},"key11":{"key12":"value8","key13":"value9"},"key14":[{"key15":"value10","key16":"value11","key17":"value12"},{"key15":"value13","key16":"value14","key17":"value15"}]}}}
dict2 = {"key1":"ab","key2":"bc","key3":"cd","key4":"de","key5":"ef","key6":"fg","key7":"gh","key8":"hi","key9":"ij","key10":"jk","key55":"kl","key11":"lm","key12":"mn","key13":"no","key14":"op","key15":"pq","key16":"qr","key17":"qs"}

def walk(dict1, dict2):
    output = {}
    for key, value in dict1.iteritems():

        if isinstance(value, dict):
            outVal = walk(value, dict2)
        elif isinstance(value, list):
            outVal = walk_list(value, dict2)
        else:
            outVal = value
        output[dict2[key]] = outVal

    return output

def walk_list(sublist, dict2):
    output = []
    for i in sublist:
        if isinstance(i, dict):
            outVal = walk(i, dict2)
        elif isinstance(i, list):
            outVal = walk_list(i, dict2)
        else:
            outVal = i
        output.append(outVal)

    return output            

mine = walk(dict1, dict2)
expecting = {"ab":{"cd":"value1","bc":"value2","de":{"ef":"value3","fg":{"gh":"value4","hi":{"ij":"value5","jk":"value6","kl":"value7"}},"lm":{"mn":"value8","no":"value9"},"op":[{"pq":"value10","qr":"value11","qs":"value12"},{"pq":"value13","qr":"value14","qs":"value15"}]}}}

print mine == expecting
+1
source

Source: https://habr.com/ru/post/1623655/


All Articles