I have a nested dictionary whose structure looks like this
{"a":{},"b":{"c":{}}}
Every key is a string and every value is a dict.
I need to replace every empty dict with "". How would I go about this?
Use recursion:
def foo(the_dict):
if the_dict == {}:
return ""
return {k : foo(v) for k,v in the_dict.items()}
Here you have a live example
Checking values for an empty dict recursively, and replacing with empty string if so.
>>> d = {"a":{},"b":{"c":{}}}
>>> def replace_empty(d):
... for k, v in d.items():
... if not bool(v):
... d[k] = ""
... else:
... d[k] = replace_empty(v)
... return d
>>> replace_empty(d)
{'a': '', 'b': {'c': ''}}
Let the dictionary be cd then:-
>>> def foo(cd):
... for x in cd:
... if cd[x] == {}:
... cd[x] = ""
... else: foo(cd[x])
... return cd
>>> cd = {"a":{},"b":{"c":{}}}
>>> foo(cd)
{'a': '', 'b': {'c': ''}}
The thinking process goes like this:-
Firstly make a processor which will process your dictionary and replace all empty dictionaries with empty strings. Then just give all the dictionaries the opportunity to meet that processor.
Related
I am trying to access a specific key in a nest dictionary, then match its value to a string in a list. If the string in the list contains the string in the dictionary value, I want to override the dictionary value with the list value. below is an example.
my_list = ['string1~', 'string2~', 'string3~', 'string4~', 'string5~', 'string6~']
my_iterable = {'A':'xyz',
'B':'string6',
'C':[{'B':'string4', 'D':'123'}],
'E':[{'F':'321', 'B':'string1'}],
'G':'jkl'
}
The key I'm looking for is B, the objective is to override string6 with string6~, string4 with string4~, and so on for all B keys found in the my_iterable.
I have written a function to compute the Levenshtein distance between two strings, but I am struggling to write an efficient ways to override the values of the keys.
def find_and_replace(key, dictionary, original_list):
for k, v in dictionary.items():
if k == key:
#function to check if original_list item contains v
yield v
elif isinstance(v, dict):
for result in find_and_replace(key, v, name_list):
yield result
elif isinstance(v, list):
for d in v:
if isinstance(d, dict):
for result in find_and_replace(key, d, name_list):
yield result
if I call
updated_dict = find_and_replace('B', my_iterable, my_list)
I want updated_dict to return the below:
{'A':'xyz',
'B':'string6~',
'C':[{'B':'string4~', 'D':'123'}],
'E':[{'F':'321', 'B':'string1~'}],
'G':'jkl'
}
Is this the right approach to the most efficient solution, and how can I modify it to return a dictionary with the updated values for B?
You can use below code. I have assumed the structure of input dict to be same throughout the execution.
# Input List
my_list = ['string1~', 'string2~', 'string3~', 'string4~', 'string5~', 'string6~']
# Input Dict
# Removed duplicate key "B" from the dict
my_iterable = {'A':'xyz',
'B':'string6',
'C':[{'B':'string4', 'D':'123'}],
'E':[{'F':'321', 'B':'string1'}],
'G':'jkl',
}
# setting search key
search_key = "B"
# Main code
for i, v in my_iterable.items():
if i == search_key:
if not isinstance(v,list):
search_in_list = [i for i in my_list if v in i]
if search_in_list:
my_iterable[i] = search_in_list[0]
else:
try:
for j, k in v[0].items():
if j == search_key:
search_in_list = [l for l in my_list if k in l]
if search_in_list:
v[0][j] = search_in_list[0]
except:
continue
# print output
print (my_iterable)
# Result -> {'A': 'xyz', 'B': 'string6~', 'C': [{'B': 'string4~', 'D': '123'}], 'E': [{'F': '321', 'B': 'string1~'}], 'G': 'jkl'}
Above can has scope of optimization using list comprehension or using
a function
I hope this helps and counts!
In some cases, if your nesting is kind of complex you can treat the dictionary like a json string and do all sorts of replacements. Its probably not what people would call very pythonic, but gives you a little more flexibility.
import re, json
my_list = ['string1~', 'string2~', 'string3~', 'string4~', 'string5~', 'string6~']
my_iterable = {'A':'xyz',
'B':'string6',
'C':[{'B':'string4', 'D':'123'}],
'E':[{'F':'321', 'B':'string1'}],
'G':'jkl'}
json_str = json.dumps(my_iterable, ensure_ascii=False)
for val in my_list:
json_str = re.sub(re.compile(f"""("[B]":\\W?")({val[:-1]})(")"""), r"\1" + val + r"\3", json_str)
my_iterable = json.loads(json_str)
print(my_iterable)
I have two dictionaries, the first is a dictionary of dictionaries.
dict = {k1:{kk1:vv1, kk2: vv2}, k2:{kkk1:vvv1, kkk2:vvv2}}
dict1 = dict['k2']
# So basically:
# dict1 = {kkk1:vvv1, kkk2:vvv2}
dict3 = {vvv1:actualv1, vvv2:actualv2}
I want the end result to be:
dict1 = {kkk1:actualv1, kkk2:actualv2}
Which is basically:
dict = {k1:{kk1:vv1, kk2: vv2}, k2:{kkk1:actualv1, kkk2:actualv2}}
So, I have tried dictionary comprehension:
{k: dict2.get(v, v) for k, v in dict1.items()}
But to no avail. I have tried to be as clear as possible. One more thing I'd like to mention is that The 'dict' contains about 400 k-v pairs. I have given an example of what I would like to achieve. Help.
Patching the dict1 alone and inplace, accordint to dict3, can be done like this:
d = dict(k1=dict(kk1='vv1', kk2='vv2'),
k2=dict(kkk1='vvv1', kkk2='vvv2'))
dict1 = d['k2']
dict3 = dict(vvv1='actualv1', vvv2='actualv2')
for k in dict1:
v = dict1[k]
try:
dict1[k] = dict3[v]
except KeyError:
pass
print d
prints:
{'k2': {'kkk2': 'actualv2', 'kkk1': 'actualv1'},
'k1': {'kk1': 'vv1', 'kk2': 'vv2'}}
You can try this:
dict = {'k1':{'kk1':'vv1', 'kk2': 'vv2'}, 'k2':{'kkk1':'vvv1', 'kkk2':'vvv2'}}
dict3 = {'vvv1':'actualv1', 'vvv2':'actualv2'}
final_data = {a:{c:dict3.get(d, d) for c, d in b.items()} for a, b in dict.items()}
Output:
{'k1': {'kk1': 'vv1', 'kk2': 'vv2'}, 'k2': {'kkk1': 'actualv1', 'kkk2': 'actualv2'}}
Ok, so you want to process a sub dict from a dict of dicts, given its key, and replace values according to a replacement dict original_value => replacement_value.
You can just do it:
def patch_dic(dic, key, dict3):
for k,v in dic[key].items(): # iterate the sub dict
for orig, repl in dict3.items(): # iterate the replacement dict
if v == orig: # if a value exists in the replacement dict
dic[key][k] = repl # just replace it
Demo:
>>> dic = {'k1':{'kk1':'vv1', 'kk2': 'vv2'}, 'k2':{'kkk1':'vvv1', 'kkk2':'vvv2'}}
>>> patch_dic(dic, 'k2', {'vvv1':'actualv1', 'vvv2':'actualv2'})
>>> print(dic)
{'k1': {'kk1': 'vv1', 'kk2': 'vv2'}, 'k2': {'kkk1': 'actualv1', 'kkk2': 'actualv2'}}
I have list which have keys of dictionary. How to access the dictionary using these keys dynamically. e.g
key_store = ['test','test1']
mydict = {"test":{'test1':"value"},"test3":"value"}
So how to access mydict using key_store I want to access mydict['test']['test1'].
Note: key_store store depth of keyword means it have keywords only its value will be dictionary like test have dictionary so it have 'test','test1'
You can do this with a simple for-loop.
def get_nested_key(keypath, nested_dict):
d = nested_dict
for key in keypath:
d = d[keypath]
return d
>>> get_nested_key(('test', 'test1'), Dict)
Add error checking as required.
Use recursion:
def get_value(d, k, i):
if not isinstance(d[k[i]], dict):
return d[k[i]]
return get_value(d[k[i]], k, i+1)
The parameters are the dictionary, the list and an index you'll be running on.
The stop condition is simple; Once the value is not a dictionary, you want to return it, otherwise you continue to travel on the dictionary with the next element in the list.
>>> key_store = ['test','test1']
>>> Dict = {"test":{'test1':"value"},"test3":"value"}
>>> def get_value(d, k, i):
... if isinstance(d[k[i]], str):
... return d[k[i]]
... return get_value(d[k[i]], k, i+1)
...
>>> get_value(Dict, key_store, 0)
'value'
You could do this with a simple dictionary reduce:
>>> mydict = {"test": {'test1': "value"}, "test3": "value"}
>>> print reduce(dict.get, ['test', 'test1'], mydict)
value
I'm working on a small framework and I've found a place where it would be beneficial to save a dictionary key as variable.
The problem I have is that the dictionary may have any number of layers, so it's not just a case of storing the final key. For example in the below I am accessing ['dig']['result'], but that could equally be ['output'] or ['some']['thing']['strange']
if result:
if self.cli_args.json:
pprint(result)
else:
print result['dig']['result']
I could save the key as a string and use eval() in something such as:
key="['test']"
test_dict = { "test" : "This works" }
eval("test_dict" + key)
>>> 'This works'
But eval is really dirty right? :-)
Is there a nice / pythonic way to do this?
To handle an arbitrary depth of key nesting, you can iterate over a sequence (e.g. tuple) of the keys:
>>> d = {'a': {'b': {'c': 'd'}}}
>>> d['a']['b']['c']
'd'
>>> keys = ('a', 'b', 'c') # or just 'abc' for this trivial example
>>> content = d
>>> for k in keys:
content = content[k]
>>> content
'd'
>>> def access(o,path):
... for k in path.split('/'):
... o = o[k]
... return o
...
>>> access({'a': {'b': {'c': 'd'}}},'a/b/c')
'd'
I am using Python 3.3. I was curious how I can make a dictionary out of a list:
Lets say my list containing strings is
list = ['a;alex', 'a;allison', 'b;beta', 'b;barney', 'd;doda', 'd;dolly']
I want to make it into a dictionary like this:
new_dict = { {'a': {'alex','allison'}}
{'b': {'beta','barney'}}
{'d': {'doda', 'dolly'}} }
so later I can print it out like this:
Names to be organized and printed:
a -> {'alex', 'allison'}
b -> {'beta', 'barney'}
d -> {'doda', 'dolly'}
How would I approach this? Many thanks in advance!
-UPDATE-
So far I have this:
reached_nodes = {}
for i in list:
index = list.index(i)
reached_nodes.update({list[index][0]: list[index]})
But it outputs into the console as:
{'a': 'a;allison', 'b': 'b;barney', 'd': 'd;dolly'}
Well, you can use defaultdict:
>>> from collections import defaultdict
>>> l = ['a;alex', 'a;allison', 'b;beta', 'b;barney', 'd;doda', 'd;dolly']
>>> var = defaultdict(list)
>>> for it in l:
a, b = it.split(';')
var[a].append(b)
>>> var
defaultdict(<type 'list'>, {'a': ['alex', 'allison'], 'b': ['beta', 'barney'], 'd': ['doda', 'dolly']})
>>> for key, item in var.items():
... print "{} -> {{{}}}".format(key, item)
...
a -> {['alex', 'allison']}
b -> {['beta', 'barney']}
d -> {['doda', 'dolly']}
If you would like to get rid of the [], then try the following:
>>> for key, value in var.items():
... print "{} -> {{{}}}".format(key, ", ".join(value))
a -> {alex, allison}
b -> {beta, barney}
d -> {doda, dolly}
If you would like the values in a set and not a list, then just do the following:
var = defaultdict(set)
And use .add instead of .append.