Python反转/反转映射

给定一个这样的字典:

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

如何能反转这张地图得到:

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

编者注: map变成了my_map以避免与内置函数map冲突。 下面有些意见可能会受到影响。

对于Python 2.7.x

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

对于Python 3+:

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

假设字典中的值是唯一的:

 dict((v, k) for k, v in my_map.iteritems()) 

如果my_map中的值不唯一:

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

尝试这个:

 inv_map = dict(zip(my_map.values(), my_map.keys())) 

(请注意, 字典视图上的Python文档明确保证.keys().values()的元素具有相同的顺序,这使得上述方法可以工作。

或者:

 inv_map = dict((my_map[k], k) for k in my_map) 

或使用Python 3.0的词典理解

 inv_map = {my_map[k] : k for k in my_map} 
 def inverse_mapping(f): return f.__class__(map(reversed, f.items())) 

另一个更实用的方法是:

 my_map = { 'a': 1, 'b':2 } dict(map(reversed, my_map.items())) 

这扩大了Python的反转/反转映射的答案,适用于字典中的值不唯一时。

 class ReversibleDict(dict): def reversed(self): """ Return a reversed dict, with common values in the original dict grouped into a list in the returned dict. Example: >>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2}) >>> d.reversed() {1: ['d'], 2: ['c', 'b', 'f'], 3: ['a', 'e']} """ revdict = {} for k, v in self.iteritems(): revdict.setdefault(v, []).append(k) return revdict 

实现是有限的,因为你不能使用reversed两次,并得到原来的回。 这是不对称的。 它使用Python 2.6进行testing。 这里是我如何使用打印结果字典的用例。

如果你宁愿使用一个set而不是一个list ,而且有一些应用程序是setdefault(v, []).append(k) ,而不是setdefault(v, []).append(k) ,使用setdefault(v, set()).add(k)

如果这些值不是唯一的,而且你是一个硬核:

 inv_map = dict( (v, [k for (k, xx) in filter(lambda (key, value): value == v, my_map.items())]) for v in set(my_map.values()) ) 

特别是对于一个大的字典,请注意,这个解决scheme远远低于Python的反转/反转映射的效率,因为它多次遍历items()

除了上面提到的其他function,如果你喜欢lambdas:

 invert = lambda mydict: {v:k for k, v in mydict.items()} 

或者,你也可以这样做:

 invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) ) 

我们也可以使用defaultdict反转带有重复键的字典:

 from collections import Counter, defaultdict def invert_dict(d): d_inv = defaultdict(list) for k, v in c.items(): d_inv[v].append(k) return d_inv text = 'aaa bbb ccc ddd aaa bbb ccc aaa' c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ddd': 1}) dict(invert_dict(c)) # {1: ['ddd'], 2: ['bbb', 'ccc'], 3: ['aaa']} 

看到这里 :

这种技术比使用dict.setdefault()的等效技术更简单快捷。

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

 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 

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

这个实现比翻转整个字典更有效率(这似乎是这个页面上最stream行的解决scheme)。 更何况,您可以根据需要添加或删除SymDict中的值,并且逆向字典将始终保持有效 – 如果您只颠倒整个字典一次,则这种情况并非如此。

这处理非独特的价值,并保留了独特的案件的大部分外观。

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

对于Python 3.x,用replaceitervalues 。 我不能赞扬这一点…这是由图标杰克build议。

添加我的2 pythonic方式:

 inv_map = dict(map(reversed, my_map.items())) 

例:

 In [7]: my_map Out[7]: {1: 'one', 2: 'two', 3: 'three'} In [8]: inv_map = dict(map(reversed, my_map.items())) In [9]: inv_map Out[9]: {'one': 1, 'three': 3, 'two': 2} 

试试这个python 2.7 / 3.x

 inv_map={}; for i in my_map: inv_map[my_map[i]]=i print inv_map 

使用zip

 inv_map = dict(zip(my_map.values(), my_map.keys())) 
 def invertDictionary(d): myDict = {} for i in d: value = d.get(i) myDict.setdefault(value,[]).append(i) return myDict print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1}) 

这将提供输出为:{1:['a','d'],2:['b'],3:['c']}

函数对于types列表的值是对称的; 当执行reverse_dict(reverse_dict(字典))时元组被转换为列表

 def reverse_dict(dictionary): reverse_dict = {} for key, value in dictionary.iteritems(): if not isinstance(value, (list, tuple)): value = [value] for val in value: reverse_dict[val] = reverse_dict.get(val, []) reverse_dict[val].append(key) for key, value in reverse_dict.iteritems(): if len(value) == 1: reverse_dict[key] = value[0] return reverse_dict 

由于字典在字典中需要一个不同于值的唯一键,所以我们必须将反转的值附加到新的特定键中包括的sorting列表中。

 def r_maping(dictionary): List_z=[] Map= {} for z, x in dictionary.iteritems(): #iterate through the keys and values Map.setdefault(x,List_z).append(z) #Setdefault is the same as dict[key]=default."The method returns the key value available in the dictionary and if given key is not available then it will return provided default value. Afterward, we will append into the default list our new values for the specific key. return Map 

快速function解决scheme非双射图(值不唯一):

 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 ) } 

从理论上讲,这应该比在命令性解决scheme中逐一添加(或附加到列表)更快。

不幸的是,这些值必须是可sorting的,groupby需要sorting。

没有什么完全不同,只是从Cookbook重新编写的食谱。 而且通过保留setdefault方法来进一步优化,而不是每次都通过实例获取:

 def inverse(mapping): ''' A function to inverse mapping, collecting keys with simillar values in list. Careful to retain original type and to be fast. >> d = dict(a=1, b=2, c=1, d=3, e=2, f=1, g=5, h=2) >> inverse(d) {1: ['f', 'c', 'a'], 2: ['h', 'b', 'e'], 3: ['d'], 5: ['g']} ''' res = {} setdef = res.setdefault for key, value in mapping.items(): setdef(value, []).append(key) return res if mapping.__class__==dict else mapping.__class__(res) 

devise为在CPython 3.x下运行,为2.xreplacemapping.items()mapping.iteritems()

在我的机器上运行速度比其他例子快一些

我在循环“for”和method'.get()'的帮助下写了这个,我把字典的名字'map'改成了'map1',因为'map'是一个函数。

 def dict_invert(map1): inv_map = {} # new dictionary for key in map1.keys(): inv_map[map1.get(key)] = key return inv_map 

如果值不唯一并且可能是散列(一维):

 for k, v in myDict.items(): if len(v) > 1: for item in v: invDict[item] = invDict.get(item, []) invDict[item].append(k) else: invDict[v] = invDict.get(v, []) invDict[v].append(k) 

如果您需要深入挖掘,那么只需一个维度即可:

 def digList(lst): temp = [] for item in lst: if type(item) is list: temp.append(digList(item)) else: temp.append(item) return set(temp) for k, v in myDict.items(): if type(v) is list: items = digList(v) for item in items: invDict[item] = invDict.get(item, []) invDict[item].append(k) else: invDict[v] = invDict.get(v, []) invDict[v].append(k) 

我会在Python 2中这样做。

 inv_map = {my_map[x] : x for x in my_map} 

对于各种字典,不pipe它们是否没有唯一的值作为键,你可以为每个值创build一个键列表

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

如果项目不是唯一的尝试这个:

  dict={} dict1={} num=int(raw_input(" how many numbers in dict?--> ")) for i in range (0,num): key=raw_input(" enter key --> ") value=raw_input("enter value --> ") dict[key]=value keys=dict.keys() values=dict.values() for b in range (0,num): keys[b],values[b]=values[b],keys[b] dict1[keys[b]]=values[b] print keys print values print dict1