给定这样的字典:
my_map = {'a': 1, 'b': 2}
如何反转这张地图以获得:
inv_map = {1: 'a', 2: 'b'}
给定这样的字典:
my_map = {'a': 1, 'b': 2}
如何反转这张地图以获得:
inv_map = {1: 'a', 2: 'b'}
Python 3+:
inv_map = {v: k for k, v in my_map.items()}
蟒蛇2:
inv_map = {v: k for k, v in my_map.iteritems()}
假设 dict 中的值是唯一的:
蟒蛇 3:
dict((v, k) for k, v in my_map.items())
蟒蛇2:
dict((v, k) for k, v in my_map.iteritems())
如果中的值my_map
不是唯一的:
蟒蛇 3:
inv_map = {}
for k, v in my_map.items():
inv_map[v] = inv_map.get(v, []) + [k]
蟒蛇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(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 的 dict 理解
inv_map = {my_map[k] : k for k in my_map}
另一种更实用的方式:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
我们还可以使用以下方法反转具有重复键的字典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()
.
这扩展了Robert的答案,适用于 dict 中的值不唯一的情况。
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 进行了测试。这是我如何使用打印结果字典的用例。
如果您宁愿使用 a 而set
不是 a list
,并且可能存在无序的应用程序对此有意义,而不是setdefault(v, []).append(k)
使用setdefault(v, set()).add(k)
.
列表和字典理解的结合。可以处理重复的键
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
例如,您有以下字典:
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 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 dict.items()}
第三个解决方案。使用还原反转方法(依赖于第二种解决方案):
# Use this code to invert dictionaries that have lists of values
dict = {value: key for key in inverted_dict for value in my_map[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'}
很多答案,但如果我们谈论的是具有非唯一值的字典,则没有找到任何干净的东西。
一个解决方案是:
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']}
我认为最好的方法是定义一个类。这是“对称字典”的实现:
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 中添加或删除值,并且您的逆向字典将始终保持有效 - 如果您只是将整个字典反转一次,则情况并非如此。
这可以处理非唯一值并保留独特案例的大部分外观。
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
.
我发现这个版本比具有 10000 个键的字典的公认版本快 10% 以上。
d = {i: str(i) for i in range(10000)}
new_d = dict(zip(d.values(), d.keys()))
我知道这个问题已经有很多很好的答案,但我想分享这个非常简洁的解决方案,它也可以处理重复值:
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中set.add
返回的事实。None
如果值不是唯一的,并且您有点铁杆:
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 a mapping的答案,因为它会循环items()
多次。
除了上面建议的其他函数,如果你喜欢 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}
inv_map= {}
for key in my_map.keys() :
val = my_map[key]
inv_map[val] = key
dict([(value, key) for key, value in d.items()])
非双射映射的快速函数解决方案(值不唯一):
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
由于字典在字典中需要一个唯一的键,而不是值,因此我们必须将反转的值附加到排序列表中,以包含在新的特定键中。
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
当前 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'}
此解决方案不检查重复项。
一些备注:
for
循环。它还避免了list comprehension
对数学不好的人使用 a ;-)接受高度投票的答案开始If the values in my_map are not unique:,我遇到了一个问题,不仅值不是唯一的,而且它们是一个列表,列表中的每个项目再次由一个三个元素的列表:一个字符串值、一个数字和另一个数字。
例子:
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)]
我会在 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 myDict
print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1})
这将提供如下输出:{1: ['a', 'd'], 2: ['b'], 3: ['c']}
def reverse_dictionary(input_dict):
out = {}
for v in input_dict.values():
for value in v:
if value not in out:
out[value.lower()] = []
for i in input_dict:
for j in out:
if j in map (lambda x : x.lower(),input_dict[i]):
out[j].append(i.lower())
out[j].sort()
return out
这段代码是这样的:
r = reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})
print(r)
{'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}
没有完全不同的东西,只是从食谱中重写了一点食谱。它通过保留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.x 替换mapping.items()
为mapping.iteritems()
在我的机器上运行比这里的其他示例快一点
我在循环'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
如果值不是唯一的并且可能是哈希(一维):
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)