dictionary Python invierte / invierte un mapeo



15 Answers

Suponiendo que los valores en el dict son únicos:

dict((v, k) for k, v in my_map.iteritems())
python dictionary mapping inverse

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.




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



Otra forma, más funcional, de:

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



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}



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.




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



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.




Prueba esto para python 2.7 / 3.x

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_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']}




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



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í.




Invierte tu diccionario:

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

print(inversed_dict_["v1"])



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.




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



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



Related