Reputation: 13185
Is it possible to use a dictionary comprehension to group keys in a dictionary?
d = {0: ("A",), 1: ("BB",), 2: ("BB",), 3: ("D",), 4: ("E",)}
l = [(0, 1, 2, 4), (3,)]
to produce:
d = {(0, 1, 2, 4): ("A","BB", "E"), (3,): ("D",)}
UPDATE:
I originally had the values as sets but have changed this to tuples. A tuple(set(x))
operation could be used when creating ("A","BB", "E")
instead of ("A","BB","BB","E")
Upvotes: 2
Views: 321
Reputation: 9007
This answer demonstrates a solution using simple loops and comprehensions. Thus, it may not be as effective as other answers.
These are your pre-defined variables, note that I removed one depth from l
(similar to DeepSpace's answer).
d = {0: ("A",), 1: ("BB",), 2: ("BB",), 3: ("D",), 4: ("E",)}
l = [(0, 1, 2, 4), (3,)]
Using normal loops:
w_normal = {}
for i in l:
temp = []
for j in i:
temp += [d[j]]
w_normal[tuple(i)] = temp
Using a dictionary comprehension (as requested):
w_comp = {tuple(i): [d[j] for j in i] for i in l}
Both values output when printed
{(0, 1, 2, 4): [('A',), ('BB',), ('BB',), ('E',)], (3,): [('D',)]}
Rather than using tuple(set(x))
to create [('A',), ('BB',), ('E',)]
, preserving [('A',), ('BB',), ('BB',), ('E',)]
will allow you to index ('BB',)
and ('E',)
with respect to the key-tuple.
However, if you're persistent you could do the tuple(set(x))
with
w_comp = {tuple(i): tuple({d[j] for j in i}) for i in l}
Upvotes: 2
Reputation: 81684
I'd use a defaultdict
. Also note that I changed the format of l
a bit, I don't think it should contain nested tuples.
d = {0: ("A",), 1: ("BB",), 2: ("BB",), 3: ("D",), 4: ("E",)}
l = [(0, 1, 2, 4), (3,)]
output = defaultdict(list)
for key_group in l:
output[key_group].extend(d[key] for key in key_group)
print(output)
# defaultdict(<class 'list'>, {(0, 1, 2, 4): [('A',), ('BB',), ('BB',), ('E',)], (3,): [('D',)]})
The values in output
are lists of tuples since tuples
are immutable. The below snippet will produce an output which is closer to the output you provided by flattening the values (except for using lists as values insted of tuples for the same reason):
d = {0: ("A",), 1: ("BB",), 2: ("BB",), 3: ("D",), 4: ("E",)}
l = [(0, 1, 2, 4), (3,)]
output = defaultdict(list)
for key_group in l:
output[key_group].extend(chain.from_iterable(set(d[key] for key in key_group)))
print(output)
# defaultdict(<class 'list'>, {(0, 1, 2, 4): ['A', 'E', 'BB'], (3,): ['D']})
For completeness, the code from OP's answer which uses defaultdict(set)
:
from collections import defaultdict
from itertools import chain
d = {0: ("A",), 1: ("BB",), 2: ("BB",), 3: ("D",), 4: ("E",)}
l = [(0, 1, 2, 4), (3,)]
output = defaultdict(set)
for key_group in l:
output[key_group].update(chain.from_iterable(d[key] for key in key_group))
print(output)
# defaultdict(<class 'set'>, {(0, 1, 2, 4): {'BB', 'A', 'E'}, (3,): {'D'}})
Upvotes: 4
Reputation: 13185
A solution similar to DeepSpace's but using a defaultdict(set).
d = {0: ("A",), 1: ("BB",), 2: ("BB",), 3: ("D",), 4: ("E",)}
l = [(0, 1, 2, 4), (3,)]
output = defaultdict(set)
for key_group in l:
output[key_group].update(d[key] for key in key_group)
Upvotes: 1