'inverting' a dict

Peter Otten __peter__ at web.de
Tue Dec 30 16:35:39 EST 2003


Irmen de Jong wrote:

> I have this dict that maps a name to a sequence of other names.
> I want to have it reversed, i.e., map the other names each to
> the key they belong to (yes, the other names are unique and
> they only occur once). Like this:

[...]

> What I'm doing is using a nested loop:
> 
> dict2={}
> for (key,value) in dict1.items():
>      for name in value:
>          dict2[name] = key
> 
> which is simple enough, but I'm hearing this little voice in
> the back of my head saying "there's a simpler solution".
> Is there? What is it? ;-)

Here's what I've come up with:

import itertools

original = {"key1": ("value1", "value2"), "key2": ("value3",)}

def forInv(original):
    result = {}
    for (key, values) in original.iteritems():
        for val in values:
            result[val] = key
    return result

def updateInv(original):
    result = {}
    for (key, values) in original.iteritems():
        result.update(dict.fromkeys(values, key))
    return result

def iterInv(original):
    result = {}
    for (key, values) in original.iteritems():
        result.update(dict(itertools.izip(values, itertools.repeat(key))))
    return result

def iterInv2(original):
    return dict(itertools.chain(*[itertools.izip(values,
itertools.repeat(key))
        for key, values in original.iteritems()]))

def compInv(original):
    return dict([(val, key) for (key, values) in original.iteritems() for
val in values])

wanted = { "value1": "key1", "value2": "key1", "value3": "key2" }

for inv in globals().values():
    if callable(inv):
        print inv.__name__,
        if inv(original) == wanted:
            print "OK"
        else:
            print "FAILED"

Conclusion: my favourite toys, itertools and list comprehensions, lead to
clumsier code - well, me at least. So I would recommend that you don't
listen to that voice.

Peter




More information about the Python-list mailing list