Reputation: 23
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
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