给定一本这样的字典:

my_map = {'a': 1, 'b': 2}

如何将此映射颠倒得到:

inv_map = {1: 'a', 2: 'b'}

当前回答

非双射地图的快速功能性解决方案(值不唯一):

from itertools import imap, groupby

def fst(s):
    return s[0]

def snd(s):
    return s[1]

def inverseDict(d):
    """
    input d: a -> b
    output : b -> set(a)
    """
    return {
        v : set(imap(fst, kv_iter))
        for (v, kv_iter) in groupby(
            sorted(d.iteritems(),
                   key=snd),
            key=snd
        )
    }

理论上,这应该比命令式解决方案中那样逐个添加到集合(或添加到列表)更快。

不幸的是,值必须是可排序的,排序是由groupby要求的。

其他回答

Python 3 +:

inv_map = {v: k for k, v in my_map.items()}

Python 2:

inv_map = {v: k for k, v in my_map.iteritems()}

列表和字典理解的结合。可以处理重复的密钥

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}

我认为最好的方法是定义一个类。下面是一个“对称字典”的实现:

class SymDict:
    def __init__(self):
        self.aToB = {}
        self.bToA = {}

    def assocAB(self, a, b):
        # Stores and returns a tuple (a,b) of overwritten bindings
        currB = None
        if a in self.aToB: currB = self.bToA[a]
        currA = None
        if b in self.bToA: currA = self.aToB[b]

        self.aToB[a] = b
        self.bToA[b] = a
        return (currA, currB)

    def lookupA(self, a):
        if a in self.aToB:
            return self.aToB[a]
        return None

    def lookupB(self, b):
        if b in self.bToA:
            return self.bToA[b]
        return None

如果需要,删除和迭代方法很容易实现。

这种实现比颠倒整个字典(这似乎是本页上最流行的解决方案)更有效。更不用说,您可以随心所欲地从SymDict中添加或删除值,并且您的反向字典将始终保持有效——如果您只是将整个字典反向一次,这是不正确的。

如果my_map中的值不是唯一的:

Python 3:

inv_map = {}
for k, v in my_map.items():
    inv_map[v] = inv_map.get(v, []) + [k]

Python 2:

inv_map = {}
for k, v in my_map.iteritems():
    inv_map[v] = inv_map.get(v, []) + [k]

这将处理非惟一值,并保留惟一情况的大部分外观。

inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}

对于Python 3。X,用值替换itervalues。