给定一本这样的字典:
my_map = {'a': 1, 'b': 2}
如何将此映射颠倒得到:
inv_map = {1: 'a', 2: 'b'}
给定一本这样的字典:
my_map = {'a': 1, 'b': 2}
如何将此映射颠倒得到:
inv_map = {1: 'a', 2: 'b'}
试试这个:
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}
假设字典中的值是唯一的:
Python 3:
dict((v, k) for k, v in my_map.items())
Python 2:
dict((v, k) for k, v in my_map.iteritems())
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()}
如果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]
要做到这一点,同时保留映射的类型(假设它是一个dict或dict子类):
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 reverse / invert映射的答案,因为它在items()上循环多次。
这扩展了Robert的回答,适用于字典中的值不是唯一的情况。
class ReversibleDict(dict):
# Ref: https://stackoverflow.com/a/13057382/
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.items():
revdict.setdefault(v, []).append(k)
return revdict
该实现的局限性在于您不能使用反转两次并获得原始数据。它本身不是对称的。它是用Python 2.6测试的。这是一个用例,我是如何使用打印结果字典。
如果你更喜欢使用集合而不是列表,并且可能存在无序的应用程序,这是有意义的,而不是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()) )
非双射地图的快速功能性解决方案(值不唯一):
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 2.7/3.x
inv_map={};
for i in my_map:
inv_map[my_map[i]]=i
print inv_map
函数对于list类型的值是对称的;执行reverse_dict(reverse_dict(dictionary))时,元组被转换为列表
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 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中添加或删除值,并且您的反向字典将始终保持有效——如果您只是将整个字典反向一次,这是不正确的。
与值不同,字典需要在字典中有一个唯一的键,因此我们必须将反向的值附加到一个sort列表中,以便包含在新的特定键中。
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
不是完全不同的东西,只是从食谱中重写了一点。它通过保留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)
设计为在CPython 3下运行。X表示2。用mapping.iteritems()替换mapping.items()
在我的机器上运行得比这里的其他例子快一些
我在循环'for'和方法'.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
我们也可以使用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。
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 ']}
列表和字典理解的结合。可以处理重复的密钥
{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循环方法:
# 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的lambda解决方案。x版本:
d1 = dict(alice='apples', bob='bananas')
d2 = dict(map(lambda key: (d1[key], key), d1.keys()))
print(d2)
结果:
{'apples': 'alice', 'bananas': 'bob'}
此解决方案不检查重复项。
一些评论:
构造可以从外部作用域访问d1,所以我们只能 传入当前键。它返回一个元组。 dict()构造函数接受一个元组列表。它 也接受映射的结果,所以我们可以跳过转换到 列表。 这个解决方案没有显式的for循环。它还避免了对那些数学不好的人使用列表理解;-)
我发现这个版本比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)}
这依赖于一个事实。在Python中add总是返回None。
有很多答案,但没有找到任何干净的东西,以防我们谈论的是一个具有非唯一值的字典。
解决办法是:
from collections import defaultdict
inv_map = defaultdict(list)
for k, v in my_map.items():
inv_map[v].append(k)
例子:
如果初始dict my_map ={“c”:1、“d”:5,' ':5 b: 10}
然后,运行上面的代码将得到:
{5: ['a', 'd'], 1: ['c'], 10: ['b']}
如果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: dict
Returns an inverted dictionary
'''
# Your code here
inv_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