Reputation: 2527
I've seen the answer to this question already Finding a key recursively in a dictionary . However, it does not give me the desired results. The problem is that it stops looking for the given key once it finds it. Meaning that if there are other instances of the key in the dictionary then these will be overlooked.
Let's say my dictionary looks something like the following:
nested_dico = {
'columns': {
'background_color': 'A5300F',
'font': {'bold': True, 'color': 'FFFFFF', 'size': 15}},
'index': {
'background_color': 'E1CDCC'},
'master': {
'align': 'center',
'background_color': 'FFFFFF',
'font': {'color': '000000', 'name': 'arial', 'size': 16},
'vertical_anchor': 'middle'}}
The desired behavior is for a function to be able to apply a given conversion to all elements within the dictionary matching the key.
For example, when running converter(nested_dico, 'size', lambda x: x*2)
I want converter
to return the same dictionary with all the size values multiplied by 2. The actual implementation I need this for is to convert all color values from Hex to RGB code.
Bonus points if you can get it working for partial strings. For example: converter(nested_dico, 'color', RGB())
will change both background_color
and color
values!
Looking ideally for an elegant pythonic solution.
Upvotes: 2
Views: 1513
Reputation: 21914
Do you want to apply a transformation function to any of the nested keys matching a pattern in a dictionary?
d = {"color": 1, 'child': {"color": 2}}
def transform(d, p, t):
for each in d:
if isinstance(d[each], dict):
transform(d[each], p, t)
if each == p:
d[each] = t(d[each])
transform(d, "color", lambda x: x+1)
If you want to generalize "how do you determine if the pattern is matching", then you can pass the logic as a function like this:
d = {"color": 1, 'child': {"background-color": 2}}
def transform(d, p, t):
for each in d:
if type(d[each]) == dict:
transform(d[each], p, t)
if p(each):
d[each] = t(d[each])
transform(d, lambda x: 'color' in x, lambda x: x+1)
The argument p
is called as a predicate
function. You can call it with 'color' in x
to handle partial strings for example.
Upvotes: 4
Reputation: 170
nested_dico = {
'columns': {
'background_color': 'A5300F',
'font': {'bold': True, 'color': 'FFFFFF', 'size': 15}},
'index': {
'background_color': 'E1CDCC'},
'master': {
'align': 'center',
'background_color': 'FFFFFF',
'font': {'color': '000000', 'name': 'arial', 'size': 16},
'vertical_anchor': 'middle'}}
def seletive_map(origin,matcher,mapper,current_keys=[]):
result = {}
for k,v in origin.items():
if matcher(current_keys + [k]):
result[k] = mapper(v)
elif hasattr(v,'items'):
result[k] = seletive_map(v,matcher,mapper,current_keys + [k])
else:
result[k] = v
return result
result = seletive_map(nested_dico,lambda keys: keys[-1] == "size",lambda x : x*2)
#result = seletive_map(nested_dico,lambda keys: "color" in keys[-1],RGB)
print result
Upvotes: 3