Shiv Sr
Shiv Sr

Reputation: 23

Nested dictionaries iterations within dictionaries using for loop

There are three different nested dictionaries:

dict1={'g1': {'s1': 'checked', 's2': '0', 'Both':'checked'}, 'g2': {'s1': '0', 's2':'checked', 'Both': 'checked'}, 'g3': {'s1': 'checked', 's2': 'checked', 'Both': 'checked'}}
dict2={'g1': {'s1': '11', 's2': '', 'Both': '13'}, 'g2': {'s1': '', 's2': '22', 'Both':'23'}, 'g3': {'s1':'31', 's2': '32', 'Both': '33'}}
dict3={"s1": {"PS":'value1'}, "s2": {"PS": 'value2'}, "Both": {"PS": 'value3'}}

Desired nested dictionary is dict4. (Note: In format of dict1 or dict2, i.e. {'g1': {'s1': "xxxx",'s2':'xxxy'}}, where xxxx and xxxy are values from below given condition.)

Description: Keys and values are common approx. and the desired output required from above three dictionaries will also must be a nested dictionary having condition if value=='checked' in dict1 then dict3 with the new key 'Msg' and value from dict2 that is having same nested key must added to the desired nested dictionary dict4 having parent key from dict1.

My code:

dict4={}  # declaring desired dictionary
for nkey,nvalue in dict1.items():
    tempDict={} #temporary dictionary to store all checked from dict1
    for key,value in nvalue.items():
        if value=='checked':
            tempDict[key]=dict3[key]
            tempDict[key]['Msg']=dict2[nkey][key]
    #in prescribed format assigning dict4
    dict4[nkey]=tempDict

Wrong Output from above code: (wrong 'Msg' values)

dict4 = {'g1': {'s1': {'PS': 'value1', 'Msg': '31'}, 'Both': {'PS': 'value3', 'Msg': '33'}}, 'g2': {'s2': {'PS': 'value2', 'Msg': '32'}, 'Both': {'PS': 'value3', 'Msg': '33'}}, 'g3': {'s1': {'PS': 'value1', 'Msg': '31'}, 's2': {'PS': 'value2', 'Msg': '32'}, 'Both': {'PS': 'value3', 'Msg': '33'}}}

Correct and desired output: (with correct 'Msg')

dict4 = {'g1': {'s1': {'PS': 'value1', 'Msg': '11'}, 'Both': {'PS': 'value3', 'Msg': '13'}}, 'g2': {'s2': {'PS': 'value2', 'Msg': '22'}, 'Both': {'PS': 'value3', 'Msg': '23'}}, 'g3': {'s1': {'PS': 'value1', 'Msg': '31'}, 's2': {'PS': 'value2', 'Msg': '32'}, 'Both': {'PS': 'value3', 'Msg': '33'}}}

As per the code above, I am trying to store all checked from dict1 to a temporary dictionary, then adding the key 'Msg' (new key) and value from dict2 then assigning dict4 in desired format (key from dict1 and value from temporary dictionary i.e. tempDict).

Issue: As I observed is that, it over writes the 'Msg' from desired dict4 and tempDict values when changing then it reflects dict4 values while inside for loop (as I have debug the code by printing values in all stages).

Please clarify and suggest the possible solution and why when the value is changing on tempDict then it reflects to the already assigned to the previous key value in dict4, i.e. when tempDict changes 'Msg' for g3 then it changes values in g1 and g2 also.

I have tried tempDict.clear() method in place of tempDict={} then dict4 output is like:

dict4={}  # declaring desired dictionary
for nkey,nvalue in dict1.items():
    tempDict={} #temporary dictionary to store all checked from dict1
    for key,value in nvalue.items():
        if value=='checked':
            tempDict[key]=dict3[key]
            tempDict[key]['Msg']=dict2[nkey][key]
    #in prescribed format assigning dict4
    dict4[nkey]=tempDict
    tempDict.clear()  

Output from above: (wrong)

dict4 = {'g1': {}, 'g2': {}, 'g3': {'s1': {'PS': 'value1', 'Msg': '31'}, 's2': {'PS': 'value2', 'Msg': '32'}, 'Both': {'PS': 'value3', 'Msg': '33'}}},

Is there any memory assigned from value issue or somewhere I wrote wrong logic?

Correct and desired output: (with correct 'Msg')

dict4 = {'g1': {'s1': {'PS': 'value1', 'Msg': '11'}, 'Both': {'PS': 'value3', 'Msg': '13'}}, 'g2': {'s2': {'PS': 'value2', 'Msg': '22'}, 'Both': {'PS': 'value3', 'Msg': '23'}}, 'g3': {'s1': {'PS': 'value1', 'Msg': '31'}, 's2': {'PS': 'value2', 'Msg': '32'}, 'Both': {'PS': 'value3', 'Msg': '33'}}}

Code 3: (same output)

dict4={}
for nkey,nvalue in dict1.items():                 
  for key,value in nvalue.items():                        
    if value=='checked':
      try:
        dict4[nkey][key]=dict3[key]
      except:
        dict4[nkey]={}
      dict4[nkey][key]=dict3[key]
      dict4[nkey][key]['Msg']=dict2[nkey][key]

Upvotes: 1

Views: 211

Answers (1)

finefoot
finefoot

Reputation: 11224

The issue is with Python's dict type being a mutable type. With tempDict[key]=dict3[key], you will put "a reference" to the already existing dict3[key] into tempDict[key]. If you change the object by accessing it via its reference from either dict, those changes will be "visible" everywhere (as both dict3[key] and tempDict[key] refer to the same object).

In other words, you access the "inner" dict via its reference in either "outer" dict so any modification which has been applied to the "inner" dict will be "visible" whichever way you use to access it. It's only one and the same object after all. After copy, you have two objects (two "inner" dict) and the two "outer" dict refer to each one of them.

More information about mutable/immutable types in Python: Immutable vs Mutable types, for example.

Regarding a solution: Good news, if you don't want both dict3[key] and tempDict[key] to refer to the same object, you can create a copy via the dict.copy method. So in your first code, the only thing you will have to change is

tempDict[key]=dict3[key]

to

tempDict[key]=dict3[key].copy()

and you'll get your desired output.

Should your dict contain further mutable types, that you want to change, you will have to create a copy of each "layer" with copy.deepcopy, for example.

Upvotes: 1

Related Questions