Python invierte / invierte un mapeo

Dado un diccionario como este:

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

¿Cómo se puede invertir este mapa para obtener:

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

NOTA my_map EDITOR: el map cambió a my_map para evitar conflictos con la función incorporada, map . Algunos comentarios pueden verse afectados a continuación.

Para Python 2.7.x

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

Para Python 3+:

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

Suponiendo que los valores en el dict son únicos:

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

Si los valores en my_map no son únicos:

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

Prueba esto:

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

(Tenga en cuenta que los documentos de Python en las vistas del diccionario garantizan explícitamente que .keys() y .values() tienen sus elementos en el mismo orden, lo que permite que el enfoque anterior funcione).

Alternativamente:

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

o usando dictaduras de Python 3.0

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

Otra forma, más funcional, de:

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

Esto expande la respuesta Python invierte / invierte una asignación , aplicándose a cuando los valores en el dict no son únicos.

 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 

La implementación está limitada en el sentido de que no se puede utilizar reversed dos veces y recuperar el original. No es simétrico como tal. Se prueba con Python 2.6. Aquí hay un caso de uso de cómo estoy usando para imprimir el dictado resultante.

Si prefiere utilizar un set que una list , y hay aplicaciones para las que esto tiene sentido, en lugar de setdefault(v, []).append(k) , use setdefault(v, set()).add(k) .

Combinación de lista y comprensión de diccionario. Puede manejar claves duplicadas

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

Añadiendo mis 2 centavos de manera pythonica:

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

Ejemplo:

 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} 

Si los valores no son únicos, y eres un poco duro:

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

Especialmente para un dictado grande, tenga en cuenta que esta solución es mucho menos eficiente que la respuesta que Python invierte / invierte en un mapeo porque recorre los items() varias veces.

También podemos revertir un diccionario con claves duplicadas usando 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']} 

Ver aqui

Esta técnica es más simple y más rápida que una técnica equivalente utilizando dict.setdefault() .

Además de las otras funciones sugeridas anteriormente, si te gustan las lambdas:

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

O, también puedes hacerlo de esta manera:

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

Esto maneja valores no únicos y conserva gran parte del aspecto del caso único.

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

Para Python 3.x, reemplaza itervalues con valores . No puedo tomar crédito por esto … fue sugerido por Icon Jack.

Creo que la mejor manera de hacer esto es definir una clase. Aquí hay una implementación de un “diccionario simétrico”:

 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 

Los métodos de eliminación e iteración son bastante fáciles de implementar si son necesarios.

Esta implementación es mucho más eficiente que invertir un diccionario completo (que parece ser la solución más popular en esta página). Por no mencionar, puedes agregar o eliminar valores de SymDict todo lo que desees, y tu diccionario inverso siempre será válido. Esto no es cierto si simplemente inviertes el diccionario completo una vez.

Usando zip

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

Por ejemplo, tienes el siguiente diccionario:

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

Y quieres conseguirlo en una forma tan invertida:

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

Primera solución . Para invertir pares de clave-valor en su diccionario use un enfoque de bucle 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) 

Segunda solución . Utilice un enfoque de comprensión de diccionario para la inversión:

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

Tercera Solución . Utilice revertir el enfoque de inversión :

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

Prueba esto para python 2.7 / 3.x

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

Yo lo haría así en 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}) 

Esto proporcionará una salida como: {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 

este código hace de esta manera:

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

La función es simétrica para valores de lista de tipos; Las tuplas se cubren en listas cuando se realiza reverse_dict (reverse_dict (diccionario))

 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 

Dado que los diccionarios requieren una clave única dentro del diccionario a diferencia de los valores, tenemos que agregar los valores invertidos en una lista de clasificación para incluirlos dentro de las nuevas claves específicas.

 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 

No es algo completamente diferente, solo una receta un poco reescrita de Cookbook. Se optimiza aún más al conservar el método setdefault , en lugar de setdefault por la instancia cada vez:

 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) 

Diseñado para ejecutarse en CPython 3.x, para 2.x reemplazar mapping.items() con mapping.iteritems()

En mi máquina corre un poco más rápido, que otros ejemplos aquí.

Si los valores no son únicos Y puede ser un hash (una dimensión):

 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) 

Y con una recursión si necesita profundizar más, solo una dimensión:

 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) 

Invierte tu diccionario:

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

Según mi comentario a la pregunta. Creo que el más fácil y un forro que funciona tanto para Python2 como para Python 3 será

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

Solución funcional rápida para mapas no biyectivos (valores no únicos):

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

En teoría, esto debería ser más rápido que agregar al conjunto (o agregarse a la lista) uno por uno, como en la solución imperativa .

Desafortunadamente, los valores tienen que ser ordenados, la clasificación es requerida por groupby.

Escribí esto con la ayuda del ciclo ‘para’ y el método ‘.get ()’ y cambié el nombre ‘mapa’ del diccionario a ‘mapa1’ porque ‘mapa’ es una función.

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

Para todo tipo de diccionarios, no importa si no tienen valores únicos para usar como claves, puede crear una lista de claves para cada valor

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

Esta no es la mejor solución, pero funciona. Digamos que el diccionario que queremos invertir es:

dictionary = {‘a’: 1, ‘b’: 2, ‘c’: 3}, entonces:

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

La salida de reverse_dictionary, debe ser {1: ‘a’, 2: ‘b’, 3: ‘c’}