This question already has answers here:
Combining 2 dictionaries with common key
(5 answers)
Closed 3 years ago.
I am not looking for something like this:
How do I merge two dictionaries in a single expression?
Generic way of updating python dictionary without overwriting the subdictionaries
Python: Dictionary merge by updating but not overwriting if value exists
I am looking for something like this:
input:
d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}
output:
new_dict = {'a': ['a'], 'b': ['b', 'c'], 'c': ['d']}
I have the following code which works but I am wondering if there is a more efficient method:
First, I create a list "unique_vals", where all the values that are present in both dicts are stored.
From this, a new dictionary is created which stores all the values present in both dictionaries
unique_vals = []
new_dict = {}
for key in list(d1.keys())+list(d2.keys()) :
unique_vals = []
try:
for val in d1[key]:
try:
for val1 in d2[key]:
if(val1 == val) and (val1 not in unique_vals):
unique_vals.append(val)
except:
continue
except:
new_dict[key] = unique_vals
new_dict[key] = unique_vals
Then, for every value in both dictionaries that are not listed in this new dictionary, these values are appended to the new dictionary.
for key in d1.keys():
for val in d1[key]:
if val not in new_dict[key]:
new_dict[key].append(val)
for key in d2.keys():
for val in d2[key]:
if val not in new_dict[key]:
new_dict[key].append(val)
Maybe with a defaultdict?
>>> d1 = {'a': 'a', 'b': 'b'}
>>> d2 = {'b': 'c', 'c': 'd'}
>>> from collections import defaultdict
>>>
>>> merged = defaultdict(list)
>>> dicts = [d1, d2]
>>> for d in dicts:
...: for key, value in d.items():
...: merged[key].append(value)
...:
>>> merged
defaultdict(list, {'a': ['a'], 'b': ['b', 'c'], 'c': ['d']})
This works with any number of dictionaries in the dicts list.
As a function:
def merge_dicts(dicts):
merged = defaultdict(list)
for d in dicts:
for key, value in d.items():
merged[key].append(value)
return merged
Here is a far simpler version:
d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}
new_dict = {key: [value] for key, value in d1.items()}
for key, value in d2.items():
try:
new_dict[key].append(value)
except:
new_dict[key] = [value]
Output:
{'a': ['a'], 'b': ['b', 'c'], 'c': ['d']}
EDIT: Solution below is for the original question, see other answers or duplicate for updated question.
A one line solution:
def merge_dicts(*dcts):
return {k: [d[k] for d in dcts if k in d] for k in {k for d in dcts for k in d.keys()}}
d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}
print(merge_dicts(d1, d2))
# {'c': ['d'], 'a': ['a'], 'b': ['b', 'c']}
Related
In Python I have a list of dictionary containing dictionaries.
list = [{a: {b:1, c:2}}, {d: {b:3, c:4}}, {a: {b:2, c:3}}]
I want one final list with dictionary that contain dictionary that will contain the sum of all dictionary with the same dictionary as the key. i.e. the result will be:
result = [{a: {b:3, c:5}}, {d: {b:3, c:4}}]
N.B: every dictionary in the list will contain same number of key, value pairs.
Code:
lst = [{'a': {'b':1, 'c':2}}, {'d': {'b':3, 'c':4}}, {'a': {'b':2, 'c':3}}]
p={}
for l in lst:
for key , val in l.items():
if key in p and val != p[key]:
p.update({key:{k: p[key].get(k, 0) + val.get(k, 0) for k in set(p[key])}})
else:
p.update(l)
Output:
{'a': {'c': 5, 'b': 3}, 'd': {'b': 3, 'c': 4}}
I don't know if it is the best way to do this, but here it goes:
First I've made a loop for to get all of the primary and secondary keys:
# list containing the data
lista = [{'a': {'b':1, 'c':2}}, {'d': {'b':3, 'c':4}}, {'a': {'b':2, 'c':3}}]
# empty list with keys
primary_keys = []
secondary_keys = []
# for each dict in the list it appends the primary key and the secondary key
for dic in lista:
for key in dic.keys():
primary_keys.append(key)
for key2 in dic[key].keys():
secondary_keys.append(key2)
# prints all the keys
print('Primary keys:',primary_keys)
print('Secondary keys:',secondary_keys)
Results:
Primary keys: ['a', 'd', 'a']
Secondary keys: ['b', 'c', 'b', 'c', 'b', 'c']
Then I've made a final dict with all the combinations:
# creates the final dict from the list
dict_final = dict.fromkeys(primary_keys)
# for all primary keys creates a secondary key
for pkey in dict_final.keys():
dict_final[pkey] = dict.fromkeys(secondary_keys)
# for all secondary keys puts a zero
for skey in dict_final[pkey].keys():
dict_final[pkey][skey] = 0
# prints the dict
print(dict_final)
Results:
{'a': {'b': 0, 'c': 0}, 'd': {'b': 0, 'c': 0}}
And later I've made a loop through each dictionary item and added to the corresponding keys in the final dict
# for each primary and secondary keys in the dic list sums into the final dict
for dic in lista:
for pkey in dict_final.keys():
for skey in dict_final[pkey].keys():
try:
dict_final[pkey][skey] += dic[pkey][skey]
except:
pass
# prints the final dict
print(dict_final)
Results:
{'a': {'b': 3, 'c': 5}, 'd': {'b': 3, 'c': 4}}
By using defaultdict, we can simplify the logic a bit:
# Using default dict
from collections import defaultdict
original_list = [{'a': {'b':1, 'c':2}}, {'d': {'b':3, 'c':4}}, {'a': {'b':2, 'c':3}}]
out = defaultdict(lambda: defaultdict(int))
for outter_dict in original_list:
for outter_key, inner_dict in outter_dict.items():
for inner_key, inner_value in inner_dict.items():
out[outter_key][inner_key] += inner_value
print(out)
out_list = [{key: dict(value) for key, value in out.items()}]
print(out_li)
Output:
defaultdict(<function <lambda> at 0x103c18a60>, {'a': defaultdict(<class 'int'>, {'b': 3, 'c': 5}), 'd': defaultdict(<class 'int'>, {'b': 3, 'c': 4})})
[{'a': {'b': 3, 'c': 5}, 'd': {'b': 3, 'c': 4}}]
Notes
out is a nested defaultdict whose values are yet defaultdict whose values are integers
After the 3 nested loops, we converted the defaultdict out to a list of dictionaries to conform the output requirement
Here are my lists:
a = {'A':'red', 'B':'blue', 'C':'cyan'}
b = {'A':[1,1,2,4], 'B':[1,2,5]}
Here is the code I have for inversion of the dictionary:
def again(dict):
tuple(value for value in dict)
result_dict = {}
for key, value in dict.items():
if not value in result_dict.keys():
result_dict[value] = []
result_dict[value].append(key)
return result_dict
The function works for dictionary labeled "a" but does not work for dictionary "b". This is because dictionary b has an unhashable data type (i.e. a list).
Running the function:
again(a)
output --> {'red': ['A'], 'blue': ['B'], 'cyan': ['C']}
I am trying to take dictionary "b" and invert it just like with dictionary "a", but I have no clue how to account for the list values with multiple integers, e.g.:
{'A' : [1, 1, 2, 4}, 'B' : [1, 2, 5]}
would return you:
{1 : ['A', 'B'], 2 : ['A', 'B'], 4 : ['A'], 5 : ['B']}
You need another for loop to iterate over the value if it is a list.
def again(d):
result = dict()
for key, value in d.items():
if isinstance(value, list):
for num in value:
if not num in result:
result[num] = list()
if key not in result[num]:
result[num].append(key)
else:
if not value in result:
result[value] = list()
result[value].append(key)
return result
>>> again({'A':'red', 'B':'blue', 'C':'cyan'})
{'red': ['A'], 'blue': ['B'], 'cyan': ['C']}
>>> again({'A':[1,1,2,4], 'B':[1,2,5]})
{1: ['A', 'B'], 2: ['A', 'B'], 4: ['A'], 5: ['B']}
Using defaultdict with if-else condition to check if dictionary value is a list:
from collections import defaultdict
def again(d):
res = defaultdict(list)
for k,v in d.items():
if isinstance(v,list):
temp = list(set([(x,k) for x in v]))
for x,y in temp:
res[x].append(y)
else:
res[v].append(k)
return dict(res)
print(again({'A':'red', 'B':'blue', 'C':'cyan'}))
print(again({'A':[1,1,2,4], 'B':[1,2,5]}))
Output:
{'red': ['A'], 'blue': ['B'], 'cyan': ['C']}
{1: ['A', 'B'], 2: ['A', 'B'], 4: ['A'], 5: ['B']}
This question already has answers here:
Inverting a dictionary with list values
(6 answers)
Closed 1 year ago.
Say I have a dictionary like this
D = {'a': [1,2,3], 'b': [2,3,4], 'c': [3,4,5]}
For each unique element present across all the lists, I want to find the associated dict keys.
The wanted output is thus:
out = {1: ['a'], 2: ['a', 'b'], 3: ['a', 'b', 'c'], 4: ['b', 'c'], 5: ['c']}
How do I do this most efficiently?
EDIT: I need to do this for a large dict with ~100 keys and each list between 50-10000 elements
You can use a collections.defaultdict:
from collections import defaultdict
out = defaultdict(list)
for k, vals in D.items():
for val in vals:
out[val].append(k)
out
# defaultdict(<class 'list'>, {1: ['a'], 2: ['a', 'b'], 3: ['a', 'b', 'c'], 4: ['b', 'c'], 5: ['c']})
Alternatively, use dict.setdefault:
out = {}
for k, vals in D.items():
for val in vals:
out.setdefault(val, []).append(k)
You could try this dictionary comprehension with a list comprehension:
>>> {val: [k for k in D.keys() if val in D[k]] for v in D.values() for val in v}
{1: ['a'], 2: ['a', 'b'], 3: ['a', 'b', 'c'], 4: ['b', 'c'], 5: ['c']}
>>>
Or you could try this for loop:
res = {}
for k, val in D.items():
for v in val:
if v in res:
res[v].append(k)
else:
res[v] = [k]
print(res)
Output:
{1: ['a'], 2: ['a', 'b'], 3: ['a', 'b', 'c'], 4: ['b', 'c'], 5: ['c']}
Use get function:
for i,j in D.items():
for k in j:
out[k] = out.get(k,[])+[i]
def recursion(input_type):
print('input_type ',input_type)
if isinstance(input_type, dict):
num = 0
for k,v in input_type.items():
if isinstance(v, dict):
print('from recursion')
recursion(v)
elif isinstance(v, list):
for j in v:
if isinstance(j, dict):
print('from recursion level 2')
recursion(j)
else:
temp_dict = {k:v}
print('type: ',type(temp_dict), k, v)
print('num',num)
num = num+1
for i in list_:
recursion(i)
How to get the interim results from the recursion.
consider the input as shown below:
input: [{'a':a, 'b':b, 'c':[{'d':d, 'e':e}]}]
Updated input: [ {'a':a, 'b':b, 'c': { 'd':d, 'e': [ {'f':f, 'g':g}, {'f':f1, 'g':g1} ] } } ]
desired output: [{'a':a, 'b':b, 'd':d, 'f':f, 'g':g, 'f_new':f1, 'g_new':g1}]
If the key is duplicate then it should update such as 'f' to 'f_new' or something like that
Thank you in advance!!
You can iterate over the dict items and if an item is a list, recursively flatten the dicts within it:
def f(o):
return {a: b for k, v in o.items() for a, b in ((i for d in (v if isinstance(v, list)
else (v,)) for i in f(d).items()) if isinstance(v, (list, dict)) else ((k, v),))}
so that given:
lst = [{'a': 'a', 'b': 'b', 'c': [{'d': 'd', 'e': 'e'}, {'f': [{'g': 'g'}]}]}]
[f(d) for d in lst] would return:
[{'a': 'a', 'b': 'b', 'd': 'd', 'e': 'e', 'g': 'g'}]
and that given:
lst = [{'a': 'a', 'b': 'b', 'c': {'d': 'd', 'e': {'f': 'f', 'g': 'g'}}}]
[f(d) for d in lst] would return:
[{'a': 'a', 'b': 'b', 'd': 'd', 'f': 'f', 'g': 'g'}]
To avoid collisions in merged keys, append _new to a duplicating key until it is found not pre-existing, in which case you cannot use comprehension:
def f(o):
output = {}
for k, v in o.items():
for a, b in ((i for d in (v if isinstance(v, list) else (v,)) for i in f(d).items())
if isinstance(v, (list, dict)) else ((k, v),)):
while a in output:
a += '_new'
output[a] = b
return output
so that given:
lst = [{'a': 'a', 'b': 'b', 'c': {'d': 'd', 'e': [{'f': 'f', 'g': 'g'}, {'f': 'f1', 'g': 'g1'}]}}]
[f(d) for d in lst] would return:
[{'a': 'a', 'b': 'b', 'd': 'd', 'f': 'f', 'g': 'g', 'f_new': 'f1', 'g_new': 'g1'}]
Demo: https://repl.it/#blhsing/NonstopSeveralActionscript
I have a dictionary looking something like this:
d = {'f1': ['a','a','b','c'],
'f2': ['b','c','d'],
'f3': ['a','c','d']}
I want to get information about how many keys have a certain value.
For example: a:2, b:1, c:3...
(And if value was in one key more than once, count only first one).
Is there a way to do it?
Everything I found was about comparing two dictionaries, but here I have one.
I searched a lot but I haven't found solution for case like this.
Thank you in advance for your help!
Slow one liner:
>>> {k:sum(1 for l in d.values() if k in l) for k in set(sum(d.values(), []))}
{'a': 2, 'd': 2, 'b': 2, 'c': 3}
This may not be the best way but is this what you are looking for?
d = {'f1': ['a','a','b','c'],'f2': ['b','c','d'],'f3': ['a','c','d']}
certain_value = 'a'
counter = 0
for key, value in d.items():
if certain_value in value:
counter += 1
print("{0} has the {1} for {2} times.".format(key, certain_value, counter))
counter = 0
Define a function genMap in your code, it will do the job
d = {
'f1': ['a', 'a', 'b', 'c'],
'f2': ['b', 'c', 'd'],
'f3': ['a', 'c', 'd']
}
def genMap(obj):
final_map = {}
for key in obj:
already_mapped = []
for value in d[key]:
if(value not in already_mapped):
already_mapped.append(value)
if(value not in final_map):
final_map[value] = 0
final_map[value] += 1
return final_map
result = genMap(d)
print(result)
Output
{
'a': 2,
'b': 2,
'c': 3,
'd': 2
}