I'd like to add the values of a dictionary to another dictionary. For example:
adict = {1: {'a': 13, 'b': 19, 'c': 15}, 2: {'a': 7, 'b': 2, 'c': 0}}
If we add {1: {'a': 3, 'b': 9, 'c': 23}} to adict
Then adict should now be:
{1: {'a': 16, 'b': 28, 'c': 38}, 2: {'a': 7, 'b': 2, 'c': 0}}
If we add {3: {'a': 4}} then adict should now be:
{1: {'a': 16, 'b': 28, 'c': 38}, 2: {'a': 7, 'b': 2, 'c': 0}, 3: {'a': 4}}
and if we add {2: {'a': 1, 'b': 8, 'c': 27, 'd': 11}}
Then adict should now be:
{1: {'a': 16, 'b': 28, 'c': 38}, 2: {'a': 8, 'b': 10, 'c': 27, 'd': 11}, 3: {'a': 4}}
What's the best way to do this?
Simple recursive function:
>>> adict = {1: {'a': 13, 'b': 19, 'c':15}, 2: {'a': 7, 'b': 2, 'c':0}}
>>> def dict_add(a,b):
... a = a.copy()
... for k,v in b.items():
... if isinstance(v,(dict,)):
... a[k] = dict_add(a.get(k,{}),v)
... else:
... a[k] = a.get(k,0) + v
... return a
...
>>> dict_add(adict,{1: {'a': 3, 'b': 9, 'c': 23}})
{1: {'a': 16, 'c': 38, 'b': 28}, 2: {'a': 7, 'c': 0, 'b': 2}}
>>> dict_add(dict_add(adict,{1: {'a': 3, 'b': 9, 'c': 23}}),{3:{'a':4}})
{1: {'a': 16, 'c': 38, 'b': 28}, 2: {'a': 7, 'c': 0, 'b': 2}, 3: {'a': 4}}
This is probably very inefficient, but here's what I came up with:
def dict_add(a, b):
result = dict(a)
for key, value in b.items():
if type(value) != dict:
result[key] = result.get(key, 0) + value
else:
result[key] = dict_add(result.get(key, {}), value)
return result
Running this code results in this:
>>> adict = {1: {'a': 13, 'b': 19, 'c':15}, 2: {'a': 7, 'b': 2, 'c':0}}
>>> bdict = {1: {'a': 3, 'b': 9, 'c': 23}}
>>>
>>> print dict_add(adict, bdict)
{1: {'a': 16, 'c': 38, 'b': 28}, 2: {'a': 7, 'c': 0, 'b': 2}}
Here is a functional solution. The rec_add function does what you ask with arbitrarily nested dictionaries.
def combine(f, d1, d2):
"""Create a new dict combining d1 and d2.
Keys appearing only in one of the input dict are copied unmodified. Values
with matching keys are combined using f and copied in the output dict."""
keys = set(d1.keys() + d2.keys())
out = { }
for key in keys:
if key in d1:
if key in d2:
out[key] = f(d1[key], d2[key])
else:
out[key] = d1[key]
else:
out[key] = d2[key]
return out
def rec_combine(f, d1, d2):
"""Recursively combine all dicts."""
def aux(v1, v2):
if isinstance(v1, (dict,)) and isinstance(v2, (dict,)):
return rec_combine(f, v1, v2)
else:
return f(v1, v2)
return combine(aux, d1, d2)
def rec_add(d1, d2):
"""Recursively sum values in d1 and d2."""
return rec_combine(lambda x, y: x + y, d1, d2)
Related
This question already has answers here:
Python Dictionary: How to update dictionary value, base on key - using separate dictionary keys
(2 answers)
Closed 1 year ago.
I have the following 2 dictionaries
a = {'a': 1, 'b': 2, 'c': 3}
b = {1: 11, 2: 22}
And I'd like to modify a into
a = {'a': 11, 'b': 22, 'c': 3}
How do I achieve this result?
You might use following dict-comprehension
a = {'a': 1, 'b': 2, 'c': 3}
b = {1: 11, 2: 22}
a = {k:b.get(v,v) for k,v in a.items()}
print(a)
output
{'a': 11, 'b': 22, 'c': 3}
Note usage of .get(v,v) so if there is not key in b original value is retained.
you can try dict comprehension
{k1: b.get(v1, v1) for k1,v1 in a.items()}
{'a': 11, 'b': 22, 'c': 3}
Try this:
a = {k: b.get(v, v) for k, v in a.items()}
try this:
a = {'a': 1, 'b': 2, 'c': 3}
b = {1: 11, 2: 22}
for k,v in a.items():
a[k] = b.get(v, v)
print(a)
Output:
{'a': 11, 'b': 22, 'c': 3}
i'm trying my code. I'm confused..How to combine these 2 dictionaries so that the value of the results is like this?
1 A 18
5 B 14
3 C 15
7 D 20
for code
d= {'A': 1, 'B': 5, 'C': 3, 'D': 7}
e= {'A': 18, 'B': 14, 'C': 15, 'D': 20}
for k,v in d.items():
print (v)
for i,(k, v) in enumerate(e.items()):
print(i,k, v)
i don't understand. Please help me. Thanks!
You can do this:
d = {'A': 1, 'B': 5, 'C': 3, 'D': 7}
e = {'A': 18, 'B': 14, 'C': 15, 'D': 20}
for k in sorted(d.keys() & e.keys()):
print(d[k], k, e[k])
The & ensures that we only use the keys present in both d and e.
Note that we need the sorted call to ensure that the dicts are indexed alphabetically in the situation where the dict keys aren't alphabetically inserted in the first place.
d= {'A': 1, 'B': 5, 'C': 3, 'D': 7}
e= {'A': 18, 'B': 14, 'C': 15, 'D': 20}
for i in d.keys():
print(d[i],i,e[i])
As the key in both dictionaries are same, so if you access one key you can easily access values from both the dictionaries and can print it in any order/format.
d= {'A': 1, 'B': 5, 'C': 3, 'D': 7}
e= {'A': 18, 'B': 14, 'C': 15, 'D': 20}
final_dictionary = {x: d.get(x, 0) + e.get(x, 0)
for x in set(d).union(e)}
print("final dictionary", str(final_dictionary))
I am a beginner in python trying to create a function that filters through my nested dictionary through by asking multiple values in a dictionary like
filtered_options = {'a': 5, 'b': "Cloth'}
For my dictionary
my_dict = {1.0:{'a': 1, 'b': "Food', 'c': 500, 'd': 'Yams'},
2.0:{'a': 5, 'v': "Cloth', 'c': 210, 'd': 'Linen'}}
If I input my dictionary in the filter function with such options I should get something that looks like
filtered_dict(my_dict, filtered_options = {'a': 5, 'b': "Cloth'})
which outputs the 2nd key and other keys with the same filtered options in my dictionary.
This should do what you want.
def dict_matches(d, filters):
return all(k in d and d[k] == v for k, v in filters.items())
def filter_dict(d, filters=None):
filters = filters or {}
return {k: v for k, v in d.items() if dict_matches(v, filters)}
Here's what happens when you test it:
>>> filters = {'a': 5, 'b': 'Cloth'}
>>> my_dict = {
... 1.0: {'a': 1, 'b': 'Food', 'c': 500, 'd': 'Yams'},
... 2.0: {'a': 5, 'b': 'Cloth', 'c': 210, 'd': 'Linen'}
... }
>>> filter_dict(my_dict, filters)
{2.0: {'b': 'Cloth', 'a': 5, 'd': 'Linen', 'c': 210}}
You can do this :
import operator
from functools import reduce
def multi_level_indexing(nested_dict, key_list):
"""Multi level index a nested dictionary, nested_dict through a list of keys in dictionaries, key_list
"""
return reduce(operator.getitem, key_list, nested_dict)
def filtered_dict(my_dict, filtered_options):
return {k : v for k, v in my_dict.items() if all(multi_level_indexing(my_dict, [k,f_k]) == f_v for f_k, f_v in filtered_options.items())}
So that:
my_dict = {1.0:{'a': 1, 'b': 'Food', 'c': 500, 'd': 'Yams'},
2.0:{'a': 5, 'b': 'Cloth', 'c': 210, 'd': 'Linen'}}
will give you:
print(filtered_dict(my_dict, {'a': 5, 'b': 'Cloth'}))
# prints {2.0: {'a': 5, 'b': 'Cloth', 'c': 210, 'd': 'Linen'}}
If I have many dictionaries that I would like to modify (e.g., to filter out some value in all of them), how can I proceed in a efficient/pythonic way?
In the following example, the filtering operation within the loop works, but the actual dictionaries are not changed/affected:
d1 = {key:val for key, val in zip(('a', 'b', 'c', 'd', 'e'), range(5))}
d2 = {key:val for key, val in zip(('a', 'b', 'c', 'd', 'e'), range(4, 9))}
for d in (d1, d2):
print d
d = {key: d[key] for key in d if d[key] != 4}
print d
print d1
print d2
# {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3}
# {'a': 0, 'c': 2, 'b': 1, 'd': 3}
# {'a': 4, 'c': 6, 'b': 5, 'e': 8, 'd': 7}
# {'c': 6, 'b': 5, 'e': 8, 'd': 7}
# {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3}
# {'a': 4, 'c': 6, 'b': 5, 'e': 8, 'd': 7}
This should do the trick:
d1 = {key:val for key, val in zip(('a', 'b', 'c', 'd', 'e'), range(5))}
d2 = {key:val for key, val in zip(('a', 'b', 'c', 'd', 'e'), range(4, 9))}
dicts = [d1, d2]
print dicts
#[{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3}, {'a': 4, 'c': 6, 'b': 5, 'e': 8, 'd': 7}]
for i, d in enumerate(dicts):
for k, v in d.items():
if v == 4:
del dicts[i][k]
print dicts
#[{'a': 0, 'c': 2, 'b': 1, 'd': 3}, {'c': 6, 'b': 5, 'e': 8, 'd': 7}]
print d1
#{'a': 0, 'b': 1, 'c': 2, 'd': 3}
print d2
#{'b': 5, 'c': 6, 'd': 7, 'e': 8}
I have 2 lists like this:
l1 = [{'a': 1, 'b': 2, 'c': 3, 'd': 4}, {'a': 5, 'b': 6, 'c': 7, 'd': 8}]
l2 = [{'a': 5, 'b': 6, 'e': 100}, {'a': 1, 'b': 2, 'e': 101}]
and I want to obtain a list l3, which is a join of l1 and l2 where values of 'a' and 'b' are equal in both l1 and l2
i.e.
l3 = [{'a': 1, 'b: 2, 'c': 3, 'd': 4, 'e': 101}, {'a': 5, 'b: 6, 'c': 7, 'd': 8, 'e': 100}]
How can I do this?
You should accumulate the results in a dictionary. You should use the values of 'a' and 'b' to form a key of this dictionary
Here, I have used a defaultdict to accumulate the entries
l1 = [{'a': 1, 'b': 2, 'c': 3, 'd': 4}, {'a': 5, 'b': 6, 'c': 7, 'd': 8}]
l2 = [{'a': 5, 'b': 6, 'e': 100}, {'a': 1, 'b': 2, 'e': 101}]
from collections import defaultdict
D = defaultdict(dict)
for lst in l1, l2:
for item in lst:
key = item['a'], item['b']
D[key].update(item)
l3 = D.values()
print l3
output:
[{'a': 1, 'c': 3, 'b': 2, 'e': 101, 'd': 4}, {'a': 5, 'c': 7, 'b': 6, 'e': 100, 'd': 8}]
Simple list operations would do the thing for you as well:
l1 = [{'a': 1, 'b': 2, 'c': 3, 'd': 4}, {'a': 5, 'b': 6, 'c': 7, 'd': 8}]
l2 = [{'a': 5, 'b': 6, 'e': 100}, {'a': 1, 'b': 2, 'e': 101}]
l3 = []
for i in range(len(l1)):
for j in range(len(l2)):
if l1[i]['a'] == l2[j]['a'] and l1[i]['b'] == l2[j]['b']:
l3.append(dict(l1[i]))
l3[i].update(l2[j])
My approach is to sort the the combined list by the key, which is keys a + b. After that, for each group of dictionaries with similar key, combine them:
from itertools import groupby
def ab_key(dic):
return dic['a'], dic['b']
def combine_lists_of_dicts(list_of_dic1, list_of_dic2, keyfunc):
for key, dic_of_same_key in groupby(sorted(list_of_dic1 + list_of_dic2, key=keyfunc), keyfunc):
combined_dic = {}
for dic in dic_of_same_key:
combined_dic.update(dic)
yield combined_dic
l1 = [{'a': 1, 'b': 2, 'c': 3, 'd': 4}, {'a': 5, 'b': 6, 'c': 7, 'd': 8}]
l2 = [{'a': 5, 'b': 6, 'e': 100}, {'a': 1, 'b': 2, 'e': 101}]
for dic in combine_lists_of_dicts(l1, l2, ab_key):
print dic
Discussion
The function ab_key returns a tuple of value for key a and b, used for sorting a groupping
The groupby function groups all the dictionaries with similar keys together
This solution is less efficient than that of John La Rooy, but should work fine for small lists
One can achieve a nice and quick solution using pandas.
l1 = [{'a': 1, 'b': 2, 'c': 3, 'd': 4}, {'a': 5, 'b': 6, 'c': 7, 'd': 8}]
l2 = [{'a': 5, 'b': 6, 'e': 100}, {'a': 1, 'b': 2, 'e': 101}]
import pandas as pd
pd.DataFrame(l1).merge(pd.DataFrame(l2), on=['a','b']).to_dict('records')