I want to merge list of dictionaries in python. The number of dictionaries contained inside the list is not fixed and the nested dictionaries are being merged on both same and different keys. The dictionaries within the list do not contain nested dictionary. The values from same keys can be stored in a list.
My code is:
list_of_dict = [{'a': 1, 'b': 2, 'c': 3}, {'a': 3, 'b': 5}, {'k': 5, 'j': 5}, {'a': 3, 'k': 5, 'd': 4}, {'a': 3} ...... ]
output = {}
for i in list_of_dict:
for k,v in i.items():
if k in output:
output[k].append(v)
else:
output[k] = [v]
Is there a shorter and faster way of implementing this?
I am actually trying to implement the most fast way of doing this because the list of dictionary is very large and then there are lots of rows with such data.
One way using collections.defaultdict:
from collections import defaultdict
res = defaultdict(list)
for d in list_of_dict:
for k, v in d.items():
res[k].append(v)
Output:
defaultdict(list,
{'a': [1, 3, 3, 3],
'b': [2, 5],
'c': [3],
'k': [5, 5],
'j': [5],
'd': [4]})
items() is a dictionary method, but list_of_dict is a list. You need a nested loop so you can loop over the dictionaries and then loop over the items of each dictionary.
ou = {}
for d in list_of_dict:
for key, value in d.items():
output.setdefault(key, []).append(value)
another shorten version can be,
list_of_dict = [{'a': 1, 'b': 2, 'c': 3}, {'a': 3, 'b': 5}, {'k': 5, 'j': 5}, {'a': 3, 'k': 5, 'd': 4}, {'a': 3}]
output = {
k: [d[k] for d in list_of_dict if k in d]
for k in set().union(*list_of_dict)
}
print(output)
{'d': [4], 'k': [5, 5], 'a': [1, 3, 3, 3], 'j': [5], 'c': [3], 'b': [2, 5]}
Python 3.9+ you can use the merge operator for this.
def merge_dicts(dicts):
result = dict()
for _dict in dicts:
result |= _dict
return result
One of the shortest way would be to
prepare a list/set of all the keys from all the dictionaries
and call that key on all the dictionary in the list.
list_of_dict = [{'a': 1, 'b': 2, 'c': 3}, {'a': 3, 'b': 5}, {'k': 5, 'j': 5}, {'a': 3, 'k': 5, 'd': 4}, {'a': 3}]
# prepare a list/set of all the keys from all the dictionaries
# method 1: use sum
all_keys = sum([[a for a in x.keys()] for x in list_of_dict], [])
# method 2: use itertools
import itertools
all_keys = list(itertools.chain.from_iterable(list_of_dict))
# method 3: use union of the set
all_keys = set().union(*list_of_dict)
print(all_keys)
# ['a', 'b', 'c', 'a', 'b', 'k', 'j', 'a', 'k', 'd', 'a']
# convert the list to set to remove duplicates
all_keys = set(all_keys)
print(all_keys)
# {'a', 'k', 'c', 'd', 'b', 'j'}
# now merge the dictionary
merged = {k: [d.get(k) for d in list_of_dict if k in d] for k in all_keys}
print(merged)
# {'a': [1, 3, 3, 3], 'k': [5, 5], 'c': [3], 'd': [4], 'b': [2, 5], 'j': [5]}
In short:
all_keys = set().union(*list_of_dict)
merged = {k: [d.get(k) for d in list_of_dict if k in d] for k in all_keys}
print(merged)
# {'a': [1, 3, 3, 3], 'k': [5, 5], 'c': [3], 'd': [4], 'b': [2, 5], 'j': [5]}
Related
I want to change the value of a key inside a 2D dictionary while looping, but the program is behaving in a way I did not expect.
So first I initiated my 2D dictionary:
dict1 = dict()
dict2 = dict()
list = ['a', 'b', 'c']
list2 = ['A', 'B', 'C']
for i in list2:
dict1[i] = []
for i in list:
dict2[i] = dict1
Now I created a nested loop to change the key by appending a value to a list:
count = 0
for i in range(3):
for j in range(3):
dict2[list[i]][list2[j]].append(count)
count += 1
print(dict2)
The outcome is as follows:
{'a': {'A': [0, 3, 6], 'B': [1, 4, 7], 'C': [2, 5, 8]}, 'b': {'A': [0, 3, 6], 'B': [1, 4, 7], 'C': [2, 5, 8]}, 'c': {'A': [0, 3, 6], 'B': [1, 4, 7], 'C': [2, 5, 8]}}
whereas I expected to see this:
{'a': {'A': [0], 'B': [1], 'C': [2]}, 'b': {'A': [3], 'B': [4], 'C': [5]}, 'c': {'A': [6], 'B': [7], 'C': [8]}}
Why is the code behaving in this way and what can I change to get the outcome that I'm looking for?
Thanks!
What #darrylg says in the comment is correct. You can also combine a number of the for-loops you are using, e.g.:
keys1 = ['a', 'b', 'c']
keys2 = ['A', 'B', 'C']
dict2 = {k1: {k2: [] for k2 in keys2} for k1 in keys1}
for count, (i, j) in enumerate((i, j) for i in range(3) for j in range(3)):
dict2[keys1[i]][keys2[j]].append(count)
or, maybe better:
for count, (k1, k2) in enumerate((k1, k2) for k1 in keys1 for k2 in keys2):
dict2[k1][k2].append(count)
or perhaps, using itertools.product:
import itertools
for count, (k1, k2) in enumerate(itertools.product(keys1, keys2)):
dict2[k1][k2].append(count)
you could write it as a one-liner, although I'd strongly suggest not doing this :-) :
dict2 = (count := -1) and {k1: {k2: [count := count+1] for k2 in 'ABC'} for k1 in 'abc'}
which given:
import pprint
pprint.pprint(dict2)
will print:
{'a': {'A': [0], 'B': [1], 'C': [2]},
'b': {'A': [3], 'B': [4], 'C': [5]},
'c': {'A': [6], 'B': [7], 'C': [8]}}
I want to merge list of dictionaries in python. The number of dictionaries contained inside the list is not fixed and the nested dictionaries are being merged on both same and different keys. The dictionaries within the list do not contain nested dictionary. The values from same keys can be stored in a list.
My code is:
list_of_dict = [{'a': 1, 'b': 2, 'c': 3}, {'a': 3, 'b': 5}, {'k': 5, 'j': 5}, {'a': 3, 'k': 5, 'd': 4}, {'a': 3} ...... ]
output = {}
for i in list_of_dict:
for k,v in i.items():
if k in output:
output[k].append(v)
else:
output[k] = [v]
Is there a shorter and faster way of implementing this?
I am actually trying to implement the most fast way of doing this because the list of dictionary is very large and then there are lots of rows with such data.
One way using collections.defaultdict:
from collections import defaultdict
res = defaultdict(list)
for d in list_of_dict:
for k, v in d.items():
res[k].append(v)
Output:
defaultdict(list,
{'a': [1, 3, 3, 3],
'b': [2, 5],
'c': [3],
'k': [5, 5],
'j': [5],
'd': [4]})
items() is a dictionary method, but list_of_dict is a list. You need a nested loop so you can loop over the dictionaries and then loop over the items of each dictionary.
ou = {}
for d in list_of_dict:
for key, value in d.items():
output.setdefault(key, []).append(value)
another shorten version can be,
list_of_dict = [{'a': 1, 'b': 2, 'c': 3}, {'a': 3, 'b': 5}, {'k': 5, 'j': 5}, {'a': 3, 'k': 5, 'd': 4}, {'a': 3}]
output = {
k: [d[k] for d in list_of_dict if k in d]
for k in set().union(*list_of_dict)
}
print(output)
{'d': [4], 'k': [5, 5], 'a': [1, 3, 3, 3], 'j': [5], 'c': [3], 'b': [2, 5]}
Python 3.9+ you can use the merge operator for this.
def merge_dicts(dicts):
result = dict()
for _dict in dicts:
result |= _dict
return result
One of the shortest way would be to
prepare a list/set of all the keys from all the dictionaries
and call that key on all the dictionary in the list.
list_of_dict = [{'a': 1, 'b': 2, 'c': 3}, {'a': 3, 'b': 5}, {'k': 5, 'j': 5}, {'a': 3, 'k': 5, 'd': 4}, {'a': 3}]
# prepare a list/set of all the keys from all the dictionaries
# method 1: use sum
all_keys = sum([[a for a in x.keys()] for x in list_of_dict], [])
# method 2: use itertools
import itertools
all_keys = list(itertools.chain.from_iterable(list_of_dict))
# method 3: use union of the set
all_keys = set().union(*list_of_dict)
print(all_keys)
# ['a', 'b', 'c', 'a', 'b', 'k', 'j', 'a', 'k', 'd', 'a']
# convert the list to set to remove duplicates
all_keys = set(all_keys)
print(all_keys)
# {'a', 'k', 'c', 'd', 'b', 'j'}
# now merge the dictionary
merged = {k: [d.get(k) for d in list_of_dict if k in d] for k in all_keys}
print(merged)
# {'a': [1, 3, 3, 3], 'k': [5, 5], 'c': [3], 'd': [4], 'b': [2, 5], 'j': [5]}
In short:
all_keys = set().union(*list_of_dict)
merged = {k: [d.get(k) for d in list_of_dict if k in d] for k in all_keys}
print(merged)
# {'a': [1, 3, 3, 3], 'k': [5, 5], 'c': [3], 'd': [4], 'b': [2, 5], 'j': [5]}
This question already has answers here:
Return a default value if a dictionary key is not available
(15 answers)
Closed 1 year ago.
I want to take the elements of a list one by one and search them in 4 different dictionaries in python. then I want to create a new dictionary and put the elements of that list as keys and the values I found from those 4 dictionaries as values?
For example:
list = ['a', 'b', 'c', 'd', 'e']
dict1 = {'a': 10, 'b': 2, 'c': 45}
dict2 = {'a': 15, 'b': 55}
dict3 = {'a': 79, 'b': 6, 'c': 3}
dict4 = {'d': 600, 'e': 30}
The result I want:
newlist = {'a': [10, 15, 79, 0],
'b': [2, 55, 6, 0],
'c': [45, 0, 3, 0],
'd': [0, 0, 0, 600],
'e': [0, 0, 0, 30]}
This dict comprehension will result in what you're looking for:
dicts = dict1, dict2, dict3, dict4
{k: [d.get(k, 0) for d in dicts] for k in list1}
Something like this?
from collections import defaultdict
list1 = ['a', 'b', 'c', 'd', 'e']
dict1 = {'a': 10, 'b': 2, 'c': 45}
dict2 = {'a':11, 'b':20, 'z':100}
def collect_values(list1, dictionaries):
result = defaultdict(list)
for key in list1:
for d in dictionaries:
result[key].append(d.get(key, 0))
return result
print(collect_values(list1, [dict1, dict2]))
Which would return
defaultdict(<class 'list'>, {'a': [10, 11], 'b': [2, 20], 'c': [45, 0], 'd': [0, 0], 'e': [0, 0]})
EDIT
If appending zeros each time the key is not found in the dictionary is undesired behavior, the function below can be used:
def collect_values(list1, dictionaries):
result = defaultdict(list)
for key in list1:
for d in dictionaries:
if key in d.keys():
result[key].append(d[key])
elif not result[key]:
result[key].append(0)
return result
Which returns
defaultdict(<class 'list'>, {'a': [10, 11], 'b': [2, 20], 'c': [45], 'd': [0], 'e': [0]})
I want to convert a list of lists to a list of dictionaries. I have a way to do it but I suspect there's a better way:
t = [[1,2,3], [4,5,6]]
keys = ['a', 'b', 'c']
[{keys[0]:l[0], keys[1]:l[1], keys[2]:l[2]} for l in t]
with output
[{'a': 1, 'c': 3, 'b': 2}, {'a': 4, 'c': 6, 'b': 5}]
This could be done with a loop, but I bet there's a function to do it even easier. From this answer I'm guessing there's a way to do it with the map command, but I'm not quite sure how.
You can use list comprehension with the dict() constructor and zip:
[dict(zip(keys, l)) for l in t ]
Demo
>>> d = [dict(zip(keys, l)) for l in t ]
>>>
>>> d
[{'a': 1, 'c': 3, 'b': 2}, {'a': 4, 'c': 6, 'b': 5}]
>>>
It can also be solved with a dictionary comprehension, this way:
>>> [{k:v for k,v in zip(keys, l)} for l in t]
[{'c': 3, 'b': 2, 'a': 1}, {'c': 6, 'b': 5, 'a': 4}]
I have the following dict:
my_dict = {'A': [1, 2], 'B': [1, 4]}
And I want to end up with a list of dicts like this:
[
{'A': 1, 'B': 1},
{'A': 1, 'B': 4},
{'A': 2, 'B': 1},
{'A': 2, 'B': 4}
]
So, I'm after the product of dict's lists, expressed as a list of dicts using the same keys as the incoming dict.
The closest I got was:
my_dict = {'A': [1, 2], 'B': [1, 4]}
it = []
for k in my_dict.keys():
current = my_dict.pop(k)
for i in current:
it.append({k2: i2 for k2, i2 in my_dict.iteritems()})
it[-1].update({k: i})
Which, apart from looking hideous, doesn't give me what I want:
[
{'A': 1, 'B': [1, 4]},
{'A': 2, 'B': [1, 4]},
{'B': 1},
{'B': 4}
]
If anyone feels like solving a riddle, I'd love to see how you'd approach it.
You can use itertools.product for this, i.e calculate cartesian product of the value and then simply zip each of the them with the keys from the dictionary. Note that ordering of a dict's keys() and corresponding values() remains same if it is not modified in-between hence ordering won't be an issue here:
>>> from itertools import product
>>> my_dict = {'A': [1, 2], 'B': [1, 4]}
>>> keys = list(my_dict)
>>> [dict(zip(keys, p)) for p in product(*my_dict.values())]
[{'A': 1, 'B': 1}, {'A': 1, 'B': 4}, {'A': 2, 'B': 1}, {'A': 2, 'B': 4}]
you can use itertools.product function within a list comprehension :
>>> from itertools import product
>>> [dict(i) for i in product(*[[(i,k) for k in j] for i,j in my_dict.items()])]
[{'A': 1, 'B': 1}, {'A': 1, 'B': 4}, {'A': 2, 'B': 1}, {'A': 2, 'B': 4}]
You can get the pairs contain your key and values with the following list comprehension :
[(i,k) for k in j] for i,j in my_dict.items()]
[[('A', 1), ('A', 2)], [('B', 1), ('B', 4)]]
Then you can use product to calculate the product of the preceding lists and then convert them to dictionary with dict function.
With itertools:
>>> from itertools import product
>>> my_dict = {'A': [1, 2], 'B': [1, 4]}
>>> keys, items = zip(*my_dict.items())
>>> [dict(zip(keys, x)) for x in product(*items)]
[{'A': 1, 'B': 1}, {'A': 1, 'B': 4}, {'A': 2, 'B': 1}, {'A': 2, 'B': 4}]
Try this:
from itertools import product
def dict_product(values, first, second):
return [
{first: first_value, second: second_value}
for first_value, second_value in product(values[first], values[second])
]
This is the result:
>>> dict_product({'A': [1, 2], 'B': [1, 4]}, 'A', 'B')
[{'A': 1, 'B': 1}, {'A': 1, 'B': 4}, {'A': 2, 'B': 1}, {'A': 2, 'B': 4}]