Reputation: 2400
Say you have a dictionary of dictionaries, but you want to copy almost the entire structure (except for the values of the innermost dictionaries). The following code can do what I want, but I am sure there's a smarter way to do this:
import sys
def main(argv=()):
# original dictionary
data = {1:{'l1': [1,2,3], 'l2': [2,1,6]}, 2: {'t1': ("w?",2), 't2': ("h!",4)}}
# new values for the innermost keys
newd = {'l1' : 1, 'l2' : 2, 't1' : 3, 't2' : 4}
copy = dict.fromkeys(data.keys(), {})
for k in copy.keys():
copy[k] = dict.fromkeys(data[k].keys(), None)
for k in copy.values():
for e in k.keys():
k[e] = newd[e]
print(data)
print(copy)
if __name__ == "__main__":
sys.exit(main())
So the code above prints:
{1: {'l2': [2, 1, 6], 'l1': [1, 2, 3]}, 2: {'t1': ('w?', 2), 't2': ('h!', 4)}}
{1: {'l2': 2, 'l1': 1}, 2: {'t1': 3, 't2': 4}}
and this is the result I expect, and yet the code above seems too verbose. One caveat is that in the real example, the values for the innermost keys are not that simple but they're numpy arrays, and so I don't want to make a deep copy of the entire structure and then replace these values.
Upvotes: 1
Views: 1659
Reputation: 180441
Using your own code, you don't need to call .keys anywhere and you can create the dicts in the first loop:
def main():
# original dictionary
data = {1:{'l1': [1,2,3], 'l2': [2,1,6]}, 2: {'t1': ("w?",2), 't2': ("h!",4)}}
# new values for the innermost keys
newd = {'l1' : 1, 'l2' : 2, 't1' : 3, 't2' : 4}
copy = dict.fromkeys(data, {})
for k in copy:
copy[k] = {key:newd[key] for key in data[k]}
Upvotes: 2
Reputation: 4236
Use copy module:
import copy
data = {1:{'l1': [1,2,3], 'l2': [2,1,6]}, 2: {'t1': ("w?",2), 't2': ("h!",4)}}
cdata = copy.deepcopy(data)
Then you'll have to modify last dicts in a copy with new values.
See the copy module for deep and shallow copying.
If you're going to do it by hand to avoid populating the last floor, recursion is the way of doing it.
See how copy module does it at least, and use dict.copy() method instead of constructing new dicts with fromkeys().
Using loops to do this limits you to exact number ofnested dictionaries. If your dictionary has fixed shape, then use loops.
Upvotes: -1
Reputation: 4186
You can use (assuming python 3 from your code):
>>> copy = {outer_key: {inner_key: newd.get(inner_key, inner_dict[inner_key]) for inner_key in inner_dict} for outer_key,inner_dict in data.items()}
>>> copy
{1: {'l1': 1, 'l2': 2}, 2: {'t1': 3, 't2': 4}}
>>> data
{1: {'l1': [1, 2, 3], 'l2': [2, 1, 6]}, 2: {'t1': ('w?', 2), 't2': ('h!', 4)}}
You can simplify newd.get(inner_key, inner_dict[inner_key])
to newd[inner_key]
if you are 100% certain that every keys are in newd
. Or to newd.get(inner_key)
if you don't care aobut loosing values that are not in newd
.
Upvotes: 2