Reputation: 959
Suppose I have a dict:
x = { "a": ["walk", "the", "dog"], "b": ["dog", "spot"], "c":["the", "spot"] }
and want to have the new dict:
y = { "walk": ["a"], "the": ["a", "c"], "dog":["a", "b"], "spot":["b","c"] }
What is the most efficient way to do this? If a solution is a few lines and is somehow made simple by a pythonic construct what is it (even if it's not most efficient)?
Note that this is different than other questions where the value is a single element and not a list.
Upvotes: 2
Views: 1108
Reputation: 488453
Not necessarily efficient, but a one liner just for fun:
{b: [k for k, w in x.iteritems() if b in w] for v in x.values() for b in v}
The idea here is to iterate over all the values in the original dictionary (for v in x.values()
), then iterate over all the items in the list (for b in v
), then use b
as the key in a dict-comprehension. The value for b
is a list comprehension [k for ...]
where the members are the keys in dictionary x
for which the value w
contains the word b
.
Because the scope is limited you can actually write v
instead of w
above, which makes it even harder to understand. :-)
(Edit to add, I'd use @Blender's. These one liners are fun, but really hard to grok.)
Upvotes: 1
Reputation: 298226
You can use defaultdict
:
from collections import defaultdict
y = defaultdict(list)
for key, values in x.items(): # .iteritems() in Python 2
for value in values:
y[value].append(key)
Upvotes: 5
Reputation: 185872
y = {}
for (k, v) in x.iteritems():
for e in v:
y.setdefault(e, []).append(k)
I presented this as an alternative to @Blender's answer, since it's what I'm accustomed to using, but I think Blender's is superior since it avoids constructing a temporary []
on every pass of the inner loop.
Upvotes: 2