lf215
lf215

Reputation: 959

efficiently swap a python dict's keys and values where the values contain one or more elements

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

Answers (3)

torek
torek

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

Blender
Blender

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

Marcelo Cantos
Marcelo Cantos

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

Related Questions