反向/反转字典映射

给定这样的字典:

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

如何将此地图反转以获得:

inv_map = {1: 'a', 2: 'b'}
715152 次浏览

试试这个:

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}

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

python3:

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

python2:

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

python3+:

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

python2:

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

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

python3:

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

python2:

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

要做到这一点,同时保留映射的类型(假设它是dictdict子类):

def inverse_mapping(f):return f.__class__(map(reversed, f.items()))

如果值不是唯一的,并且你有点硬核:

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

特别是对于一个大的判词,请注意,这个解决方案的效率远远低于答案Python反向/反转映射,因为它多次循环items()

这扩展了答案由罗伯特,适用于当字典中的值不唯一时。

class ReversibleDict(dict):
def reversed(self):"""Return a reversed dict, with common values in the original dictgrouped 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进行了测试。这里是我用来打印结果字典的用例。

如果你更愿意使用set而不是list,并且可能存在无序的应用程序,而不是setdefault(v, []).append(k),请使用setdefault(v, set()).add(k)

除了上面建议的其他功能,如果你喜欢lambdas:

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

或者,你也可以这样做:

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

另一种更实用的方式:

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

非双射映射的快速函数解决方案(值不唯一):

from itertools import imap, groupby
def fst(s):return s[0]
def snd(s):return s[1]
def inverseDict(d):"""input d: a -> boutput : 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 2.7/3. x

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

函数对于list类型的值是对称的;元组在执行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

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

class SymDict:def __init__(self):self.aToB = {}self.bToA = {}
def assocAB(self, a, b):# Stores and returns a tuple (a,b) of overwritten bindingscurrB = Noneif a in self.aToB: currB = self.bToA[a]currA = Noneif b in self.bToA: currA = self.aToB[b]
self.aToB[a] = bself.bToA[b] = areturn (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中添加或删除值,并且您的逆字典将始终保持有效——如果您简单地反转整个字典一次,这是不正确的。

由于与值不同,字典需要字典中的一个唯一键,因此我们必须将颠倒的值附加到排序列表中,以包含在新的特定键中。

def r_maping(dictionary):List_z=[]Map= {}for z, x in dictionary.iteritems(): #iterate through the keys and valuesMap.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

不是完全不同的东西,只是从Cookbook中重写了一点食谱。它通过保留setdefault方法进行了进一步优化,而不是每次都通过实例获得它:

def inverse(mapping):'''A function to inverse mapping, collecting keys with simillar valuesin 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.setdefaultfor key, value in mapping.items():setdef(value, []).append(key)return res if mapping.__class__==dict else mapping.__class__(res)

设计在CPython 3. x下运行,对于2. x将mapping.items()替换为mapping.iteritems()

在我的机器上运行得比其他例子快一点

我在循环'for'和方法'. get()'的帮助下编写了这个,我将字典的名称'map'更改为'map1',因为'map'是一个函数。

def dict_invert(map1):inv_map = {} # new dictionaryfor key in map1.keys():inv_map[map1.get(key)] = keyreturn inv_map

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

from collections import Counter, defaultdict
def invert_dict(d):d_inv = defaultdict(list)for k, v in d.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()的等效技术更简单、更快。

如果值不是唯一的,并且可能是哈希(一维):

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)

这处理非唯一值并保留了唯一案例的大部分外观。

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

对于Python 3. x,将itervalues替换为values

我会在python 2中这样做。

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

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

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

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

例如,您有以下字典:

my_dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}

你想得到它在这样一个颠倒的形式:

inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}

第一解决方案.要反转字典中的键值类型对,请使用for-loop方法:

# Use this code to invert dictionaries that have non-unique values
inverted_dict = dict()for key, value in my_dict.items():inverted_dict.setdefault(value, list()).append(key)

第二解决方案.使用字典理解方法进行反转:

# Use this code to invert dictionaries that have unique values
inverted_dict = {value: key for key, value in my_dict.items()}

第三种解决方案.使用恢复反转方法(依赖于第二个解决方案):

# Use this code to invert dictionaries that have lists of values
my_dict = {value: key for key in inverted_dict for value in my_map[key]}

当前python 3. x版本的lambda解决方案:

d1 = dict(alice='apples', bob='bananas')d2 = dict(map(lambda key: (d1[key], key), d1.keys()))print(d2)

结果:

{'apples': 'alice', 'bananas': 'bob'}

此解决方案不检查重复项。

备注:

  • lambda构造可以从外部作用域访问d1,因此我们只传入当前键。它返回一个元组。
  • 字典()构造函数接受元组列表。它也接受map的结果,因此我们可以跳过转换为列表。
  • 此解决方案没有显式的for循环。它还避免对那些数学不好的人使用list comprehension;-)

我发现这个版本比接受的具有10000个键的字典版本快10%以上。

d = {i: str(i) for i in range(10000)}
new_d = dict(zip(d.values(), d.keys()))

这里有另一种方法来做到这一点。

my_map = {'a': 1, 'b': 2}
inv_map= {}for key in my_map.keys() :val = my_map[key]inv_map[val] = key

字典值是集合的情况。比如:

some_dict = {"1":{"a","b","c"},"2":{"d","e","f"},"3":{"g","h","i"}}

反过来会喜欢:

some_dict = {vi: k  for k, v in some_dict.items() for vi in v}

输出是这样的:

{'c': '1','b': '1','a': '1','f': '2','d': '2','e': '2','g': '3','h': '3','i': '3'}

我知道这个问题已经有了很多很好的答案,但我想分享这个非常简洁的解决方案,它也可以处理重复的值:

def dict_reverser(d):seen = set()return {v: k for k, v in d.items() if v not in seen or seen.add(v)}

这依赖于set.add在Python中总是返回None的事实。

很多答案,但没有找到任何干净的东西,以防我们谈论具有非唯一值的字典

解决办法是:

from collections import defaultdict
inv_map = defaultdict(list)for k, v in my_map.items():inv_map[v].append(k)

示例:

如果初始字典my_map = {'c': 1, 'd': 5, 'a': 5, 'b': 10}

然后,运行上面的代码将得到:

{5: ['a', 'd'], 1: ['c'], 10: ['b']}
dict([(value, key) for key, value in d.items()])

如果my_map中的值不是唯一的:开始,我遇到了一个问题,不仅值不是唯一的,而且它们是一个列表,列表中的每个项目再次由三个元素组成的列表:一个字符串值,一个数字和另一个数字。

示例:

mymap['key1']给你:

[('xyz', 1, 2),('abc', 5, 4)]

我只想用键切换字符串值,将两个数字元素保持在同一个位置。那么你只需要另一个嵌套的for循环:

inv_map = {}for k, v in my_map.items():for x in v:# with x[1:3] same as x[1], x[2]:inv_map[x[0]] = inv_map.get(x[0], []) + [k, x[1:3]]

示例:

inv_map['abc']现在给你:

[('key1', 1, 2),('key1', 5, 4)]

即使您在原始字典中有非唯一值,这也有效。

def dict_invert(d):'''d: dictReturns an inverted dictionary'''# Your code hereinv_d = {}for k, v in d.items():if v not in inv_d.keys():inv_d[v] = [k]else:inv_d[v].append(k)inv_d[v].sort()print(f"{inv_d[v]} are the values")        
return inv_d