Reputation: 43447
I am trying to write a dictionary comprehension.
I have a dictionary like this one:
main_dict = {
'A' : {'key1' : 'valueA1', 'key2' : 'valueA2'},
'B' : {'key2' : 'valueB2', 'key3' : 'valueB3'},
'C' : {'key3' : 'valueC3', 'key1' : 'valueC1'}}
I want to perform the following logic:
d = {}
for k_outer, v_outer in main_dict.items():
for k_inner, v_inner in v_outer.items():
if k_inner in d.keys():
d[k_inner].append([k_outer, v_inner])
else:
d[k_inner] = [[k_outer, v_inner]]
Which yields the following result:
{'key3': [['C', 'valueC3'], ['B', 'valueB3']],
'key2': [['A', 'valueA2'], ['B', 'valueB2']],
'key1': [['A', 'valueA1'], ['C', 'valueC1']]}
(I know I could use defaultdict(list)
but this is just an example)
I want to perform the logic using a dict-comprehension, so far I have the following:
d = {k : [m, v] for m, x in main_dict.items() for k, v in x.items()}
This does not work, it only gives me the following output:
{'key3' : ['B', 'valueB3'],
'key2' : ['B', 'valueB2'],
'key1' : ['C', 'valueC1']}
Which is the last instance found for each inner_key...
I am at a loss of how to perform this nested list-comprehension correctly. I have tried multiple variations, all worse than the last.
Upvotes: 0
Views: 183
Reputation: 43447
in the end, this is what i used:
from collections import defaultdict
d = defaultdict(list)
for m, x in main_dict.items():
for k, v in x.items():
d[k].append((m, v))
Upvotes: 0
Reputation: 22619
One option is to use itertools.groupby
from itertools import groupby
from operator import itemgetter
main_dict = {
'A' : {'key1' : 'valueA1', 'key2' : 'valueA2'},
'B' : {'key2' : 'valueB2', 'key3' : 'valueB3'},
'C' : {'key3' : 'valueC3', 'key1' : 'valueC1'}}
## Pull inner key, outer key and value and sort by key (prior to grouping)
x = sorted([(k2, [k1, v2]) for k1, v1 in main_dict.items() for k2, v2, in v1.items()])
## Group by key. This creates an itertools.groupby object that can be iterated
## to get key and value iterables
xx = groupby(x, key=itemgetter(0))
for k, g in xx:
print('{0} : {1}'.format(k, [r[1] for r in list(g)]))
Depending on your data and performance requirements, sorting may not be ideal so it's worth profiling.
Further, it does not result in a dict as specified, but a groupby object. That might be 'dict-like' enough for your needs; Iterating it yields key and iterables.
Upvotes: 0
Reputation: 173
Using three dictionary comprehensions to achieve such task, the third dict-comprehension is to combine the first two dicts:
e = {k : [m, v] for m, x in main_dict.items() for k, v in x.items()}
f = {k : [m, v] for m, x in main_dict.items() for k, v in x.items() if [m,v] not in e.values()}
g = {k1 : [m, v] for k1,m in e.items() for k2,v in f.items() if k1==k2}
Upvotes: 1
Reputation: 250951
You can try something like this:
In [61]: main_dict
Out[61]:
{'A': {'key1': 'valueA1', 'key2': 'valueA2'},
'B': {'key2': 'valueB2', 'key3': 'valueB3'},
'C': {'key1': 'valueC1', 'key3': 'valueC3'}}
In [62]: keys=set(chain(*[x for x in main_dict.values()]))
In [64]: keys
Out[64]: set(['key3', 'key2', 'key1'])
In [63]: {x:[[y,main_dict[y][x]] for y in main_dict if x in main_dict[y]] for x in keys}
Out[63]:
{'key1': [['A', 'valueA1'], ['C', 'valueC1']],
'key2': [['A', 'valueA2'], ['B', 'valueB2']],
'key3': [['C', 'valueC3'], ['B', 'valueB3']]}
A more readable solution using dict.setdefault
:
In [81]: d={}
In [82]: for x in keys:
for y in main_dict:
if x in main_dict[y]:
d.setdefault(x,[]).append([y,main_dict[y][x]])
....:
In [83]: d
Out[83]:
{'key1': [['A', 'valueA1'], ['C', 'valueC1']],
'key2': [['A', 'valueA2'], ['B', 'valueB2']],
'key3': [['C', 'valueC3'], ['B', 'valueB3']]}
Upvotes: 2