python dictionary mapping inverse

Python invierte/invierte un mapeo



dictionary mapping (30)

Añadiendo mis 2 centavos de forma pitónica:

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}

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.


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 podrías hacerlo de esta manera:

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


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


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 quieras, y tu diccionario inverso siempre será válido, esto no es cierto si simplemente inviertes todo el diccionario una vez.


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


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


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


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. Here hay un caso de uso de cómo estoy usando para imprimir el dictado resultante.

Si prefiere usar 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) .


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.


Invierte tu diccionario:

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


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


Lo haría así en python 2.

inv_map = {my_map[x] : x for x in my_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 bajo 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í.


Otra forma, más funcional, de:

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


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


Para todo tipo de diccionario, 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()}


Prueba esto para python 2.7 / 3.x

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


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}


Según mi comentario a la pregunta. Creo que el más sencillo y un trazador de líneas que funciona tanto para Python2 como para Python 3 será

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


Si los artículos no son únicos, prueba esto:

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


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)


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)


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 se repite en los items() varias veces.


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.


Suponiendo que los valores en el dict son únicos:

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


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 here

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


Usando zip

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


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


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


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