Python反向/反转映射

时间:2009-01-27 14:46:10

标签: python dictionary mapping inverse

给出一个像这样的字典:

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

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

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

编辑注意: map已更改为my_map,以避免与内置函数map发生冲突。有些评论可能会受到影响。

37 个答案:

答案 0 :(得分:750)

对于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()}

答案 1 :(得分:165)

假设dict中的值是唯一的:

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

答案 2 :(得分:114)

如果my_map中的值不唯一:

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

答案 3 :(得分:40)

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

答案 4 :(得分:31)

试试这个:

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

(请注意,the Python docs on dictionary views明确保证.keys().values()的元素顺序相同,这样才能实现上述方法。)

可替换地:

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

或使用python 3.0的dict comprehensions

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

答案 5 :(得分:18)

另一种更实用的方式:

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

答案 6 :(得分:7)

这扩展了答案Python reverse / invert a mapping,适用于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进行测试。 Here是我用于打印结果字典的用例。

如果您更倾向于使用set而不是list,并且有些应用程序可以使用setdefault(v, []).append(k),而不是setdefault(v, set()).add(k),请使用{{1}}。

答案 7 :(得分:7)

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

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

答案 8 :(得分:5)

加上我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}

答案 9 :(得分:5)

我们也可能使用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']}  

请参阅here

  

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

答案 10 :(得分:4)

如果值不是唯一的,那么你就是一个小硬核:

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

答案 11 :(得分:3)

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

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

或者,你也可以这样做:

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

答案 12 :(得分:3)

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

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

对于Python 3.x,将 itervalues 替换为。 我不能相信这一点......它是由Icon Jack提出的。

答案 13 :(得分:2)

字典值是一个集合的情况。喜欢:

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

答案 14 :(得分:2)

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

d = {i: str(i) for i in range(10000)}

new_d = dict(zip(d.values(), d.keys()))

答案 15 :(得分:2)

例如,您具有以下字典:

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 = dictio()
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]}

答案 16 :(得分:2)

使用zip

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

答案 17 :(得分:2)

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

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中添加或删除值,并且您的反向字典将始终保持有效 - 如果您只是将整个字典翻转一次,则情况并非如此。

答案 18 :(得分:1)

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

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 的事实。

答案 19 :(得分:1)

我会在python 2中这样做。

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

答案 20 :(得分:1)

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:[&# 39; C']}

答案 21 :(得分:1)

  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']}

答案 22 :(得分:1)

尝试使用python 2.7 / 3.x

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

答案 23 :(得分:0)

反转你的字典:

dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
inversed_dict_ = {val: key for key, val in dict_.items()}

print(inversed_dict_["v1"])

答案 24 :(得分:0)

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

解决方案是:

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, 'a': 5, 'b': 10}

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

{5: ['a', 'd'], 1: ['c'], 10: ['b']}

答案 25 :(得分:0)

这是另一种方法。

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

inv_map= {}
for key in my_map.keys() :
    val = my_map[key]
    inv_map[val] = key

答案 26 :(得分:0)

当前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,因此我们仅 传入当前密钥。它返回一个元组。
  • dict()构造函数接受一个元组列表。它 也接受地图的结果,因此我们可以跳过转换为 列表。
  • 此解决方案没有明确的for循环。它还可以避免对数学不好的人使用list comprehension;-)

答案 27 :(得分:0)

根据我对问题的评论。我认为同时适用于Python2和Python 3的最简单的方法是

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

答案 28 :(得分:0)

函数对于类型列表的值是对称的;执行反向字典(反向字典(字典))

时,元组将转换为列表
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

答案 29 :(得分:0)

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

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)

答案 30 :(得分:0)

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

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

答案 31 :(得分:0)

不是完全不同的东西,只是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)

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

在我的机器上运行速度比这里的其他示例快一点

答案 32 :(得分:-1)

我是在周期的帮助下写的,因为'和方法' .get()'我更改了名称' map'字典中的地图1' map1'因为' map'是一个功能。

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

答案 33 :(得分:-1)

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

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

理论上,这应该比在imperative solution中逐个添加到集合(或附加到列表)更快。

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

答案 34 :(得分:-3)

这不是最好的解决方案,但它确实有效。假设我们要反转的词典是:

dictionary = {'a':1,'b':2,'c':3},然后:

dictionary = {'a': 1, 'b': 2, 'c': 3}
reverse_dictionary = {}
for index, val in enumerate(list(dictionary.values())):
    reverse_dictionary[val] = list(dictionary.keys())[index]

reverse_dictionary的输出应为{1:'a',2:'b',3:'c'}

答案 35 :(得分:-3)

对于所有类型的字典,无论它们是否没有唯一值用作键,您都可以为每个值创建键列表

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

答案 36 :(得分:-5)

如果项目不是唯一的,请尝试:

     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