Replace empty dicts in nested dicts - python

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

Get specific key of a nested iterable and check if its value exists in a list

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)

How to make in-place changes to values between two dictionaries provided the value in dictionary1 is the same as Key in dictionary2?

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

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

Save a dictionary key as a variable

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'

Making a dictionary from a list of strings (creating keys from the elements of the list)

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.

Categories

Resources