convert list of keys to nested dictionary - python

I'm trying to figure out how to create, for example, a dictionary that looks like this: d[keys[0]][keys[1]][keys[2]] from a list like this : keys = ["key1", "key2", "key3"] ...
I've tried the following:
keys = ["key1", "key2", "key3"]
d = {}
d_ref= d
for key_num, key in enumerate(keys):
if key_num < len(keys)-1:
d[key] = {}
d_ref = d[key]
else:
d_ref[key] = []
print(d)
but it results in this:
{'key1': {}, 'key2': {'key3': []}}
I'm aiming for this output:
{'key1' : { 'key2' : { "key3" : [] } } }
Update
Thanks to wim for the answer that led me to my desired result:
keys = ["key1", "key2", "key3"]
d = []
for key in reversed(keys):
d = {key: d}
print(d)

Just a simple for-loop should do the trick
>>> d = {}
>>> for k in reversed(keys):
... d = {k: d}
...
>>> d
{'key1': {'key2': {'key3': {}}}}
(edit: OP changed the question after posting) Should you want a list as initial value, just change the first assignment:
>>> d = []
>>> for k in reversed(keys):
... d = {k: d}
...
>>> d
{'key1': {'key2': {'key3': []}}}

After an edit made by the OP, the solution is now a one-liner:
result = reduce(lambda obj, key: {key: obj}, reversed(keys), [])
# {'key1': {'key2': {'key3': []}}}
Or with some functional programming:
from functools import reduce
keys = ["key1", "key2", "key3"]
result = reduce((lambda obj, key: {key: obj}), reversed(keys), dict())
print(result)
# {'key1': {'key2': {'key3': {}}}}

I agree with #Ajax1234 that this problem has a recursive flavor to it but I think it can be done much simpler code than his solution:
keys = ["key1", "key2", "key3"]
def nest(keys, value):
key, *rest = keys
if rest:
value = nest(rest, value)
return {key: value}
print(nest(keys, []))

You can use recursion:
def get_dictionary(s, d):
if not s[1:]:
return {s[0]:d}
else:
if not d:
return get_dictionary(s[1:], {s[0]:[]})
else:
return get_dictionary(s[1:], {s[0]:d})
print(get_dictionary(["key1", "key2", "key3"][::-1], {}))
Output:
{'key1': {'key2': {'key3': []}}}

Related

How can I get list of values of keys in list of dicts in python?

I have a list of dicts:
[{"app1": "value1"},{"app2": "value2"},{"app1": "value3"},{"app1": "value4"}, {"app3": "value5"}]
How can I get all values of a certain key in a list?
So for example for "app1" it should become something like:
{"app1":["value1", "value3", "value4"]}
For "app2" it just becomes:
{"app2":["value2"]}
Use a defaultdict with a nested for loop
from collections import defaultdict
d = defaultdict(list)
lst = [{"app1": "value1"},{"app2": "value2"},{"app1": "value3"},{"app1": "value4"}, {"app3": "value5"}]
for i in lst:
for k,v in i.items():
d[k].append(v)
print(dict(d))
{'app1': ['value1', 'value3', 'value4'], 'app2': ['value2'], 'app3': ['value5']}
You can use a list comprehension to get all the values for a given key:
>>> data = [{"app1": "value1"},{"app2": "value2"},{"app1": "value3"},{"app1": "value4"}, {"app3": "value5"}]
>>> {"app1": [d["app1"] for d in data if "app1" in d]}
{'app1': ['value1', 'value3', 'value4']}
And if you want to accumulate it all into a single dict that's just putting the list comprehension inside a dict comprehension:
>>> {k: [d[k] for d in data if k in d] for d in data for k in d}
{'app1': ['value1', 'value3', 'value4'], 'app2': ['value2'], 'app3': ['value5']}
a = [{"app1": "value1"},{"app2": "value2"},{"app1": "value3"},{"app1": "value4"}, {"app3": "value5"}] #list of dicts
k = "app1" #key to look for
out = {k: []}
for item in a:
for key in list(item):
if key == k:
out[k].append(item[key])
print(out)
{'app1': ['value1', 'value3', 'value4']}

Why key error is combining while combining List of dictionary with same keys

I have a list of dictionary
dictio =[{'key1':'value1'}, {'key1':'value2'}, {'key1':'value3'}, {'key2':'value4'}, {'key2':'value5'}]
My desired out
{key1:[value1, value2, value3], key2:[value4, value5]}
My code throwing key error
{ k:[d[k] for d in dictio ] for k in dictio[0] }
i got solution from stack
d = {
k: [d.get(k) for d in dictio ]
for k in set().union(*dictio )
}
In this case out is having none
{'k2': [None, None, None, 'v4', 'v5'], 'k1': ['v1', 'v2', 'v3', None, None]}
Try:
{ k:[d[k] for d in dicts if k in d] for k in set().union(*dicts) }
Your code throws, because some dicts don't have all keys (for example key1 in fourth dictionary). if k in d amends that alloing to continue only those, that have.
EDIT: you need to union your dicts as well, otherwise you won't get all keys, only those present in first dictionary.
If you can guarantee the specified order of list items, you can use itertools.groupby:
{k[0]: [d[k[0]] for d in g] for k, g in groupby(d, lambda x: tuple(x))}
Example:
from itertools import groupby
d = [{'key1':'value1'}, {'key1':'value2'}, {'key1':'value3'}, {'key2':'value4'}, {'key2':'value5'}]
print({k[0]: [d[k[0]] for d in g] for k, g in groupby(d, lambda x: tuple(x))})
# {'key1': ['value1', 'value2', 'value3'], 'key2': ['value4', 'value5']}
You iterate over the dictionaries with for d in dict, and each time you use d.get(k). If a dictionary does not contain that key, it returns None, hence these are the Nones in the list.
I suggest you use a defaultdict instead, like:
from collections import defaultdict
result = defaultdict(list)
for subd in mydicts:
for k, v in subd.items():
result[k].append(v)
If you want to get rid of the "default" behavior after constructing the dictionary, you can wrap the result in a new dictionary, like:
result = dict(result)
so for the given sample dictionary, this will yield:
>>> result
defaultdict(<class 'list'>, {'key1': ['value1', 'value2', 'value3'], 'key2': ['value4', 'value5']})
>>> dict(result)
{'key1': ['value1', 'value2', 'value3'], 'key2': ['value4', 'value5']}
The above will work if dictionaries have multiple keys, etc. Furthermore we only make one pass over the list of dictionaries.
Note: please do not name your variables after builtin functions/classes like dict, since now you overwrite the reference to the dict class.
Code from your original post need slight modification to get it working as intended
dictio =[{'key1':'value1'}, {'key1':'value2'}, {'key1':'value3'}, {'key2':'value4'}, {'key2':'value5'}]
d = {
k: [d.get(k) for d in dictio if d.get(k) is not None]
for k in set().union(*dictio )
}
print(d)
Output:
{'key1': ['value1', 'value2', 'value3'], 'key2': ['value4', 'value5']}
Note usage of is not None for checking, which according to PEP-8 is the preferred way.
Different way to print
super_dict = {}
for d in dictio:
for l, m in d.items():
super_dict.setdefault(l, []).append(m)
super_dict
{'key1': ['value1', 'value2', 'value3'], 'key2': ['value4', 'value5']}
with collection set
import collections
super_dict1 = collections.defaultdict(set)
for d in dictio:
for k, v in d.items():
super_dict1[k].add(v)
dict(super_dict1)
{'key1': {'value1', 'value2', 'value3'}, 'key2': {'value4', 'value5'}}
list comprehension
combined_key_set= {key for d in dictio for key in d}
su_di = {key : [d[key] for d in dictio if key in d] for key in combined_key_set}
su_di
{'key2': ['value4', 'value5'], 'key1': ['value1', 'value2', 'value3']}
comprehension
{key : [d[key] for d in dictio if key in d] for key in [key for d in dictio for key in d]}

How to merge two nested dict in python?

I have two nested dictionary data. I want to merge them to create one dictionary in python.
Dictionary data :
dict1 = {'employee':{'dev1': 'Roy'}}
dict2 = {'employee':{'dev2': 'Biswas'}}
Now I trying to create a dictionary like bellow from them.Required Output
dict_output = {'employee':{
'dev1': 'Roy',
'dev2': 'Biswas'
}
}
my try:
import json
dict1 = {'employee':{'dev1': 'Roy'}}
dict2 = {'employee':{'dev2': 'Biswas'}}
dict1.update(dict2)
print(json.dumps(dict1, indent=2))
Output:
{
"employee": {
"dev2": "Biswas"
}
}
I am unable to merge both the dictionary.Need help to merge them
This code is to support slightly different meaning of "merge". Let's say we have a nested dictionary:
dict1 = {'employee':{'devs':{'python':{'dev1':'Roy'}}}}
dict2 = {'employee':{'devs':{'cpp':{'dev1':'Biswas'}}}}
In this case the simple loop solution returns:
{'employee': {'devs': {'cpp': {'dev1': 'Biswas'}}}}
While the "intuitive" answer should be:
{'employee': {'devs': {'python': {'dev1': 'Roy'}, 'cpp': {'dev1': 'Biswas'}}}}
This is just a simple example, the real example may be much more complex.
Below is my attempt for such a nested dictionary. It works for nested data using recursion. And it also has some restrictions. For example if dict1 and dict2 have the same value which is not dictionary, dict2 has priority. On the other hand if dict1 contains dictionary and dict2 contains value with the same key, the priority is upon dict1 and dict2 is ignored. Other restrictions will require code changes.
def merge_dict(dict1, dict2):
for key, val in dict1.items():
if type(val) == dict:
if key in dict2 and type(dict2[key] == dict):
merge_dict(dict1[key], dict2[key])
else:
if key in dict2:
dict1[key] = dict2[key]
for key, val in dict2.items():
if not key in dict1:
dict1[key] = val
return dict1
dict1 = merge_dict(dict1, dict2)
You can just update the inner dictionary.
>>> dict1 = {'employee':{'dev1': 'Roy'}}
>>> dict2 = {'employee':{'dev2': 'Biswas'}}
>>>
>>> for key in dict1:
... if key in dict2:
... dict1[key].update(dict2[key])
...
>>> dict1
{'employee': {'dev2': 'Biswas', 'dev1': 'Roy'}}
Here's a solution that should work even if both dictionaries have different keys, and you want to keep them all.
from collections import defaultdict
dict1 = {'employee': {'dev1': 'Roy'}, 'aKeyNotInDict2': {}}
dict2 = {'employee': {'dev2': 'Biswas'}, 'aKeyNotInDict1': {}}
merged_dict = defaultdict(dict)
merged_dict.update(dict1)
for key, nested_dict in dict2.items():
merged_dict[key].update(nested_dict)
print(dict(merged_dict))
Output:
{
'employee': {'dev2': 'Biswas', 'dev1': 'Roy'},
'aKeyNotInDict2': {},
'aKeyNotInDict1': {}
}
#use a dict comprehension. Adding {} in get() is to set a default return value if the key doesn't exist in dict1
{k:dict(dict1.get(k,{}).items() + v.items()) for k,v in dict2.items()}
Out[689]: {'employee': {'dev1': 'Roy', 'dev2': 'Biswas'}}
#Alternatively, a less readable way to merge the dicts using the dict constructor.
{k:dict(dict1.get(k,{}), **v) for k,v in dict2.items()}
Out[690]: {'employee': {'dev1': 'Roy', 'dev2': 'Biswas'}}
Maybe you can try naapc package as follows:
>>> from naapc import NDict
>>> dict1 = NDict({'employee':{'dev1': 'Roy'}})
>>> dict2 = {'employee':{'dev2': 'Biswas'}}
>>> dict1.update(dict2)
>>> print(dict1)
{
"employee": {
"dev1": "Roy",
"dev2": "Biswas"
}
}
In case you want a normal dict:
normal_dict = deepcopy(dict1.raw_dict)
To install:
pip install naapc
doc in: https://github.com/eiphy/naapc
def m3(a,b):
if not isinstance(a,dict) and not isinstance(b,dict):return b
for k in b:
if k in a :
a[k] = m3(a[k], b[k])
else: a[k] = b[k]
return a
d1 = {1:{"a":"A"}, 2:{"b":"B"}}
d2 = {2:{"c":"C"}, 3:{"d":"D"}}
d3 = {1:{"a":{1}}, 2:{"b":{2}}}
d4 = {2:{"c":{222}}, 3:{"d":{3}}}
d5 = {'employee':{'dev1': 'Roy'}}
d6 = {'employee':{'dev2': 'Biswas'}}
print(m3(d1,d2))
print(m3(d3,d4))
print(m3(d5,d6))
"""
Output :
{1: {'a': 'A'}, 2: {'b': 'B', 'c': 'C'}, 3: {'d': 'D'}}
{1: {'a': {1}}, 2: {'b': {2}, 'c': {222}}, 3: {'d': {3}}}
{'employee': {'dev1': 'Roy', 'dev2': 'Biswas'}}
"""
Explanation:
If a and b are not dictionaries, return b
For each key in b, if the key is in a, then merge the values of the key in a and b.
If the key is not in a, then add the key and value to a.
Return a.
But yes, The best and shortest way is this:
def m4(a,b):
for k in a:
a.get(k).update(b.get(k, {}))
return a
Explanation:
The function m4 takes two dictionaries as input.
The function iterates through the first dictionary
and updates the values of the first dictionary with
the values of the second dictionary.
The function returns the first dictionary.
[key1 == key2 and dict1.get(key1).update(dict2.get(key2))
for key1, key2 in zip(dict1, dict2)]
print dict1

Combining 2 dictionaries with common key

I have two dictionaries and need to combine the values of similar keys in them. Here's an example:
dict1 = {'key1':[value11,value12,value13] , 'key2':[value21,value22,value23]}
dict2 = {'key1':[value14,value15] , 'key2':[value24,value25]}
I used :
dict3 = {}
for key in (dict1.viewkeys() | dict2.keys()):
if key in dict1: dict3.setdefault(key, []).append(dict1[key])
if key in dict2: dict3.setdefault(key, []).append(dict2[key])
which gives me:
dict3 = {'key1':[[value11,value12,value13],[value14,value15]] , 'key2':[[value21,value22,value23],[value24,value25]]}
What I want is a simple one like:
Desired output :
dict3 = {'key1':[value11,value12,value13,value14,value15] , 'key2':[value21,value22,value23,value24,value25]}
All you need to do is to modify append to extend which will then add the elements of the list rather than adding the list itself. See the list docs for more details on the difference between append and extend.
dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23']}
dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}
dict3 = {}
for key in set().union(dict1, dict2):
if key in dict1: dict3.setdefault(key, []).extend(dict1[key])
if key in dict2: dict3.setdefault(key, []).extend(dict2[key])
print(dict3)
# {'key2': ['value21', 'value22', 'value23', 'value24', 'value25'], 'key1': ['value11', 'value12', 'value13', 'value14', 'value15']}
Alternatively you could use a collections.defaultdict with the default set to list as shown below.
from collections import defaultdict
dict3 = defaultdict(list)
for key in set().union(dict1, dict2):
for dic in [dict1, dict2]:
if key in dic:
dict3[key] += dic[key]
You can do it much simpler but if you want to use your code just change append to extend
dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23']}
dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}
dict3 = {}
for key in (dict1.viewkeys() | dict2.keys()):
if key in dict1: dict3.setdefault(key, []).extend(dict1[key])
if key in dict2: dict3.setdefault(key, []).extend(dict2[key])
print dict3
output:
{'key2': ['value21', 'value22', 'value23', 'value24', 'value25'], 'key1': ['value11', 'value12', 'value13', 'value14', 'value15']}
You can read this post about the difference ov append to extend
Here is a generic method on which you can pass as many dict as you want as parameter.
>>> def mix_dict(*args):
res = {}
for d in args:
if not isinstance(d, dict):
continue
for k, v in d.iteritems():
res.setdefault(k, [])
if isinstance(v, list):
res[k].extend(v)
else:
res[k].append(v)
return res
>>> dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23']}
>>> dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}
>>> dict3 = mix_dict(dict1, dict2)
>>> print dict3
... {'key1': ['value11', 'value12', 'value13', 'value14', 'value15'],
'key2': ['value21', 'value22', 'value23', 'value24', 'value25']}
Here is another way to do this.
You can support merging N dicts of lists into a single dict of lists with this function:
def mergeDoLs(*dicts):
def flatten(LoL):
return [e for l in LoL for e in l]
rtr={k:[] for k in set(flatten(d.keys() for d in dicts))}
for k, v in flatten(d.items() for d in dicts):
rtr[k].extend(v)
return rtr
To use:
>>> dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23'], 'key3':[1]}
>>> dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}
>>> dict3 = {'key3':[2]}
>>> mergeDoLs(dict1, dict2, dict3)
{'key3': [1, 2], 'key2': ['value21', 'value22', 'value23', 'value24', 'value25'], 'key1': ['value11', 'value12', 'value13', 'value14', 'value15']}
Use dict.update() to merge two dictionaries keys: dict1['key1'].update(dict2['key1'])

find Key for value in python when key associated with multiple values

For a dictionary of the type
{'key1': ['v1','v2','v3', ...],
'key2': ['v2','v4', ...],
... }
How do I
Find any key associated with a value v
Print that k:[value set] pair to a new dictionary
# answer to 1st question
keys_with_value = [k for k, v in old_dict.iteritems() if "whatever_value" in v]
# answer to 2nd question
new_dict = {}
for k in keys_with_value:
new_dict[k] = old_dict[k]
Example:
>>> old_dict = {'key1':['v1','v2','v3'], 'key2':['v2','v4']}
>>> keys_with_value = [k for k, v in old_dict.iteritems() if "v2" in v]
>>> new_dict = {}
>>> for k in keys_with_value:
new_dict[k] = old_dict[k]
>>> new_dict
{'key2': ['v2', 'v4'], 'key1': ['v1', 'v2', 'v3']}
>>> new_dict = {}
>>> keys_with_other_value = [k for k, v in old_dict.iteritems() if "v1" in v]
>>> for k in keys_with_other_value:
new_dict[k] = old_dict[k]
>>> new_dict
{'key1': ['v1', 'v2', 'v3']}
Actually it's faster and simpler to answer the second question (put any matching pairs found into a new_dictionary) first, then just extract the list of keys from it to answer the first question.
old_dict = {'key1': ['v1','v2','v3','v56','v99'],
'key2': ['v2','v4','v42','v17'],
'key3': ['v0','v3','v4','v17','v49'],
'key4': ['v23','v14','v42'],
}
v = 'v42'
new_dict = dict(pair for pair in old_dict.iteritems() if v in pair[1])
print 'new_dict:', new_dict
# new_dict: {'key2': ['v2', 'v4', 'v42', 'v17'], 'key4': ['v23', 'v14', 'v42']}
keys_with_value = new_dict.keys()
print 'keys_with_value:', keys_with_value
# keys_with_value: ['key2', 'key4']
In python 3 it's even nicer:
>>> old_dict = {'key1':['v1','v2','v3'], 'key2':['v2','v4']}
>>> keys_with_value = [k for k, v in old_dict.items() if "v2" in v]
>>> new_dict = {k: v for k, v in old_dict.items() if "v2" in v}
Same result as Daniel DiPaolo has. Note the .items() instead of .iteritems().

Categories

Resources