dict1 = {a: 5, b: 7}
dict2 = {a: 3, c: 1}
result {a:8, b:7, c:1}
How can I get the result?
this is a one-liner that would do just that:
dict1 = {'a': 5, 'b': 7}
dict2 = {'a': 3, 'c': 1}
result = {key: dict1.get(key, 0) + dict2.get(key, 0)
for key in set(dict1) | set(dict2)}
# {'c': 1, 'b': 7, 'a': 8}
note that set(dict1) | set(dict2) is the set of the keys of both your dictionaries. and dict1.get(key, 0) returns dict1[key] if the key exists, 0 otherwise.
this works on a more recent python version:
{k: dict1.get(k, 0) + dict2.get(k, 0) for k in dict1.keys() | dict2.keys()}
You can use collections.Counter which implements addition + that way:
>>> from collections import Counter
>>> dict1 = Counter({'a': 5, 'b': 7})
>>> dict2 = Counter({'a': 3, 'c': 1})
>>> dict1 + dict2
Counter({'a': 8, 'b': 7, 'c': 1})
if you really want the result as dict you can cast it back afterwards:
>>> dict(dict1 + dict2)
{'a': 8, 'b': 7, 'c': 1}
Here is a nice function for you:
def merge_dictionaries(dict1, dict2):
merged_dictionary = {}
for key in dict1:
if key in dict2:
new_value = dict1[key] + dict2[key]
else:
new_value = dict1[key]
merged_dictionary[key] = new_value
for key in dict2:
if key not in merged_dictionary:
merged_dictionary[key] = dict2[key]
return merged_dictionary
by writing:
dict1 = {'a': 5, 'b': 7}
dict2 = {'a': 3, 'c': 1}
result = merge_dictionaries(dict1, dict2)
result will be:
{'a': 8, 'b': 7, 'c': 1}
A quick dictionary comprehension that should work on any classes which accept the + operator. Performance might not be optimal.
{
**dict1,
**{ k:(dict1[k]+v if k in dict1 else v)
for k,v in dict2.items() }
}
Here is another approach but it is quite lengthy!
d1 = {'a': 5, 'b': 7}
d2 = {'a': 3, 'c': 1}
d={}
for i,j in d1.items():
for k,l in d2.items():
if i==k:
c={i:j+l}
d.update(c)
for i,j in d1.items():
if i not in d:
d.update({i:j})
for m,n in d2.items():
if m not in d:
d.update({m:n})
Think it's much simpler.
a={'a':3, 'b':5}
b= {'a':4, 'b':7}
{i:a[i]+b[i] for i in a.keys()}
Output: {'a': 7, 'b': 12}
Related
I have the following dictionary:
my_dict = {"A":0, "B":[1,2], "C":3}
I am trying to split this into a list of 2 dictionaries that encompass each possible value. For example:
#Desired result
[{"A":0, "B":1, "C":3}, {"A":0, "B":2, "C":3}]
I am able to get a list of each needed dictionary, in hopes I can then loop through the list and merge dictionaries using update(). This will overwrite the key "B"and only create a single dict.
Here is what I have done:
dict_list = []
my_dict = {"A":0, "B":[1,2], "C":3}
for k, v in my_dict.items():
if type(v) == list:
for i in v:
dict1 = {k:i}
dict_list.append(dict1)
if type(v) != list:
dict2 = {k:v}
dict_list.append(dict2)
new_dict = {}
for d in dict_list:
new_dict.update(d)
print(new_dict)
Output:
{'A':0, 'B':2, 'C':3}
This is overwriting the key 'B' and creating only one dictionary based on the last value.
It's pretty easy if your dict can have only one list.
>>> my_dict = {"A":0, "B":[1,2], "C":3}
>>> k, lst = next((k, v) for k, v in my_dict.items() if isinstance(v, list))
>>> [{**my_dict, k:x} for x in lst]
[{'A': 0, 'B': 1, 'C': 3}, {'A': 0, 'B': 2, 'C': 3}]
It's a bit trickier if your dict can have multiple lists.
>>> from itertools import product
>>>
>>> my_dict = {"A":0, "B":[1,2], "C":[3, 4]}
>>> lists_kv = ([(k, x) for x in v] for k, v in my_dict.items() if isinstance(v, list))
>>> [{**my_dict, **dict(x)} for x in product(*lists_kv)]
[{'A': 0, 'B': 1, 'C': 3},
{'A': 0, 'B': 1, 'C': 4},
{'A': 0, 'B': 2, 'C': 3},
{'A': 0, 'B': 2, 'C': 4}]
Having a dict like:
x = {
'1': {'a': 1, 'b': 3},
'2': {'a': 2, 'b': 4}
}
I'd like to have a new key total with the sum of each key in the subdictionaries, like:
x['total'] = {'a': 3, 'b': 7}
I've tried adapting the answer from this question but found no success.
Could someone shed a light?
Assuming all the values of x are dictionaries, you can iterate over their items to compose your new dictionary.
from collections import defaultdict
x = {
'1': {'a': 1, 'b': 3},
'2': {'a': 2, 'b': 4}
}
total = defaultdict(int)
for d in x.values():
for k, v in d.items():
total[k] += v
print(total)
# defaultdict(<class 'int'>, {'a': 3, 'b': 7})
A variation of Patrick answer, using collections.Counter and just update since sub-dicts are already in the proper format:
from collections import Counter
x = {
'1': {'a': 1, 'b': 3},
'2': {'a': 2, 'b': 4}
}
total = Counter()
for d in x.values():
total.update(d)
print(total)
result:
Counter({'b': 7, 'a': 3})
(update works differently for Counter, it doesn't overwrite the keys but adds to the current value, that's one of the subtle differences with defaultdict(int))
You can use a dictionary comprehension:
x = {'1': {'a': 1, 'b': 3}, '2': {'a': 2, 'b': 4}}
full_sub_keys = {i for b in map(dict.keys, x.values()) for i in b}
x['total'] = {i:sum(b.get(i, 0) for b in x.values()) for i in full_sub_keys}
Output:
{'1': {'a': 1, 'b': 3}, '2': {'a': 2, 'b': 4}, 'total': {'b': 7, 'a': 3}}
from collections import defaultdict
dictionary = defaultdict(int)
x = {
'1': {'a': 1, 'b': 3},
'2': {'a': 2, 'b': 4}
}
for key, numbers in x.items():
for key, num in numbers.items():
dictionary[key] += num
x['total'] = {key: value for key, value in dictionary.items()}
print(x)
We can create a default dict to iterate through each of they key, value pairs in the nested dictionary and sum up the total for each key. That should enable a to evaluate to 3 and b to evaluate to 7. After we increment the values we can do a simple dictionary comprehension to create another nested dictionary for the totals, and make a/b the keys and their sums the values. Here is your output:
{'1': {'a': 1, 'b': 3}, '2': {'a': 2, 'b': 4}, 'total': {'a': 3, 'b': 7}}
I have 2 dicts like:
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}
The merging result I want should be:
z = {3: {'a':1}, 2: {'a':3, 'b':1, 'c':2}}
I tried dict(x.items() + y.items()) and Counter, but only get
{2: {'a': 2, 'c': 2}, 3: {'a': 1}}
as a result.
How can I merge dict whose value is also a dict itself?
I have explained that the difference between How to merge two Python dictionaries in a single expression?
is that my dict's value is also a dict.
What about this:
For Python2.x:
from collections import Counter
y = {2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
x = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}
t=x.copy()
print(dict({k: (dict(Counter(t.pop(k, None)) + Counter(v))) for k, v in y.items()},**t))
Result:
{1: {'a': 1, 'b': 1}, 2: {'a': 3, 'c': 2, 'b': 1}, 3: {'a': 1}}
For Python3.5+:
{**{k: (dict(Counter(t.pop(k, None)) + Counter(v))) for k, v in y.items()},**t}
Here you have a possible solution. Although it doesn't use any library, it is quite complex.
Also it will work with any two dictionaries, independently on which is the largest.
{key: {ikey: x.get(key, {}).get(ikey, 0) + y.get(key, {}).get(ikey, 0)
for ikey in x.get(key, {}).keys()+y.get(key, {}).keys()}
for key in x.keys()+y.keys()}
Output:
{2: {'a': 3, 'b': 1, 'c': 2}, 3: {'a': 1}}
Suppose for any same depth for a certain key, in two dicts the values are of same type (both dict or both number, i don't know how to define merging a number into a dict).
def merge(d1, d2):
for i in d2:
if i not in d1:
continue
if isinstance(d1[i], dict) and isinstance(d2[i], dict):
merge(d1[i], d2[i])
else:
d2[i] += d1[i]
d1.pop(i)
for j in d1:
d2[j] = d1[j]
It's straightforward but maybe not elegant.
Use collections.Counter to "merge" the items you want to merge (only the common keys), and leave the others intact, using a double ternary expression in a dict comprehension, iterating on the union of the keys:
import collections
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}
# pre-compute common keys, one-liners are not the ultimate goal in life!
common_keys = set(x) & set(y)
# now generate the merged dict
result = {k:collections.Counter(x[k])+collections.Counter(y[k]) if k in common_keys else x[k] if k in x else y[k] for k in set(x)|set(y)}
print(result)
result:
{2: Counter({'a': 3, 'c': 2, 'b': 1}), 3: {'a': 1}}
Note: we could have avoided computing the common keys beforehand by replacing:
if k in common_keys
by
if k in x and k in y
This works:
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}
def key_merge (dict1, dict2):
## function which checks for any matching keys, and merges them
if len(dict1.keys()) == 0 or len(dict2.keys()) == 0:
return {}
else:
for key in dict1.keys():
if key in dict2.keys():
return {key:{ k: dict1[key].get(k, 0) + dict2[key].get(k, 0) for k in set(dict1[key])|set(dict2[key]) }}
z = {**x, **y, **key_merge(x, y)}
Again, up to you if it's elegant!
I don't know what your definition of 'elegantly' is but assuming you mean readable then perhaps this way will suit you.
from collections import Counter
def counter_dict(in_dict):
"""
Create a dict of Counters from a dict of dicts.
"""
return dict((k, Counter(v)) for (k, v) in in_dict.items())
def merge_counter_dicts(a, b):
"""
Create a dict of Counters from two dicts of Counters.
Where keys exist in both counts are summed.
"""
out_dict = a.copy()
for k in b.keys():
out_dict[k] = out_dict.setdefault(k, Counter()) + b[k]
return out_dict
x = {2: {'a': 1, 'b': 1}}
y = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}
xc = counter_dict(x)
xy = counter_dict(y)
print merge_counter_dicts(xc, xy)
# What about something like this:
# merge_nested_dicts.py
# tested under Python3.6
# assuming dict_02 overwrites dict_01
# one liner functional style
def deep_merge(dict_01, dict_02):
return {k: {**dict_01.get(k), **dict_02.get(k)} if k in dict_01 and
isinstance(dict_01.get(k), dict) and
isinstance(dict_02.get(k), dict) else v
for k, v in {**dict_01, **dict_02}.items()}
if __name__ == '__main__':
y = {2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
x = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}
print(x)
print(y)
print(deep_merge(x, y))
'''
{3: {'a': 1}, 2: {'a': 2, 'c': 2}}
{2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
{3: {'a': 1}, 2: {'a': 1, 'c': 2, 'b': 1}, 1: {'a': 1, 'b': 1}}
'''
Suppose I am give a list of dictionaries, where
dict1 = dict(a = 2, b = 5, c = 7)
dict2 = dict(c = 5, d = 5, e = 1)
dict3 = dict(e = 2, f = 4, g = 10)
list_of_dictionaries = [dict1, dict2, dict3]
How would I be able to, find the value of the highest index (aka the latest dictionary)?
So if I were to write a method to delete an item from the list of dictionaries, let's say I want to delete c from the dictionary.
How would I be able to delete the c from the second dictionary instead of the first?
The key is reversing through the list with reverse indexing (a_list[::-1]).
From there once you find any dictionary that matches the requirements alter it and quit the function or loop - hence the early returns.
This code:
def get_last(bucket,key):
for d in bucket[::-1]:
if key in d.keys():
return d[key]
return None
def set_last(bucket,key,val):
for d in bucket[::-1]:
if key in d.keys():
d[key] = val
return
def pop_last(bucket,key):
out = None
for d in bucket[::-1]:
if key in d.keys():
return d.pop(key)
dict1 = {'a': 2, 'b': 5, 'c': 7}
dict2 = {'c': 5, 'd': 5, 'e': 1}
dict3 = {'e': 2, 'f': 4, 'g': 10}
list_of_dictionaries = [dict1, dict2, dict3]
print get_last(list_of_dictionaries ,'c')
set_last(list_of_dictionaries ,'c',7)
print list_of_dictionaries
popped = pop_last(list_of_dictionaries ,'c')
print popped
print list_of_dictionaries
Gives:
5
[{'a': 2, 'c': 7, 'b': 5}, {'c': 7, 'e': 1, 'd': 5}, {'e': 2, 'g': 10, 'f': 4}]
7
[{'a': 2, 'c': 7, 'b': 5}, {'e': 1, 'd': 5}, {'e': 2, 'g': 10, 'f': 4}]
I am not exactly sure what you mean but I wan to show you a couple of things that might help:
First here is how your dictionaries should look like:
dict1 = {"a" :2, "b" : 5, "c" :7}
dict2 = {"c" :5, "d" :5, "e" :1}
dict3 = {"e" :2, "f" :4, "g" :10}
Then you asked this: "How would I be able to delete the c from the second dictionary instead of the first?"
You can do delete it this way:
del dict2["c"]
Lets say I have two dictionaries:
a = {'a': 1, 'b': 2, 'c': 3}
b = {'b': 2, 'c': 3, 'd': 4, 'e': 5}
What's the most pythonic way to find the non mutual items between the two of them such that for a and b I would get:
{'a': 1, 'd': 4, 'e': 5}
I had thought:
{key: b[key] for key in b if not a.get(key)}
but that only goes one way (b items not in a) and
a_only = {key: a[key] for key in a if not b.get(key)}.items()
b_only = {key: b[key] for key in b if not a.get(key)}.items()
dict(a_only + b_only)
seams very messy. Any other solutions?
>>> dict(set(a.iteritems()) ^ set(b.iteritems()))
{'a': 1, 'e': 5, 'd': 4}
Try with the symetric difference of set() :
out = {}
for key in set(a.keys()) ^ set(b.keys()):
out[key] = a.get(key, b.get(key))
diff = {key: a[key] for key in a if key not in b}
diff.update((key,b[key]) for key in b if key not in a)
just a bit cheaper version of what you have.
>>> a = {'a': 1, 'b': 2, 'c': 3}
>>> b = {'b': 2, 'c': 3, 'd': 4, 'e': 5}
>>> keys = set(a.keys()).symmetric_difference(set(b.keys()))
>>> result = {}
>>> for k in keys: result[k] = a.get(k, b.get(k))
...
>>> result
{'a': 1, 'e': 5, 'd': 4}
Whether this is less messy than your version is debatable, but at least it doesn't re-implement symmetric_difference.