Python invertir / invertir una asignación


Dado un diccionario así:

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

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

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

NOTA del EDITOR: map cambiado a my_map para evitar conflictos con la función integrada, map. Algunos comentarios pueden verse afectados a continuación.

Author: Brian M. Hunt, 2009-01-27

29 answers

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()}
 638
Author: SilentGhost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-14 16:21:01

Asumiendo que los valores en el diccionario son únicos:

dict((v, k) for k, v in my_map.iteritems())
 160
Author: Rick Teachey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-21 12:51:50

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)
 107
Author: Robert Rossney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-21 12:52:19
def inverse_mapping(f):
    return f.__class__(map(reversed, f.items()))
 33
Author: fs.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-05 10:41:30

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 las comprensiones dict de python 3.0

inv_map = {my_map[k] : k for k in my_map}
 29
Author: sykora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-21 12:51:33

Otra forma, más funcional:

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
 17
Author: Brendan Maguire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-05 14:51:23

Esto se expande sobre la respuesta Python invierte / invierte una asignación, aplicándose a cuando los valores en el diccionario 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 que no puede usar reversed dos veces y recuperar el original. No es simétrico como tal. Se prueba con Python 2.6. Aquí es un caso de uso de cómo estoy usando para imprimir el dictado resultante.

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

 6
Author: A-B-B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:41

Añadir mis 2 centavos de python manera:

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}
 5
Author: Amit Kushwaha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-03 05:39:53

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

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 dict grande, tenga en cuenta que esta solución es mucho menos eficiente que la respuesta Python invierte / invierte una asignación porque hace bucles sobre items() varias veces.

 4
Author: pcv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:43

También podemos invertir 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 aquí :

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

 4
Author: irudyak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-26 23:14:08

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

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
 4
Author: SVJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-19 03:28:14

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

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

O, usted podría hacerlo de esta manera también:

invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
 3
Author: RussellStewart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-08 21:28:48

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, reemplace itervaluespor values. No puedo tomar el crédito por esto... fue sugerido por Icon Jack.

 3
Author: user1495,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-25 20:29:24

Creo que la mejor manera de hacer esto es definir una clase. Aquí está 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 se necesitan.

Esta implementación es mucho más eficiente que invertir un diccionario entero (que parece ser la solución más popular en esta página). Sin mencionar que puede agregar o eliminar valores de su SymDict tanto como desee, y su diccionario inverso siempre permanecerá válido -- esto no es cierto si simplemente inviertes todo el diccionario una vez.

 2
Author: NcAdams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-28 07:18:45

Usando zip

inv_map = dict(zip(my_map.values(), my_map.keys()))
 2
Author: Kwaw Annor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-11 22:26:46

Pruebe esto para python 2.7/3.x

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_map
 1
Author: dhvlnyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-21 12:56:08

Lo haría de esa manera en python 2.

inv_map = {my_map[x] : x for x in my_map}
 1
Author: genghiscrade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-02 22:24:05
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']}

 1
Author: RVR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-30 10:11:43
  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 así:

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']}
 1
Author: Shb8086,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-14 16:06:43

La función es simétrica para valores de tipo list; las tuplas se cubren con 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
 0
Author: Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-24 12:29:56

Dado que los diccionarios requieren una clave única dentro del diccionario a diferencia de los valores, tenemos que anexar los valores invertidos en una lista de tipos para ser incluidos 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
 0
Author: EyoelD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-09 01:38:16

No es algo completamente diferente, solo una receta reescrita de Cookbook. Además, se optimiza conservando el método setdefault, en lugar de cada vez que lo obtiene a través de la instancia:

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 ser ejecutado bajo CPython 3.x, para 2.x sustitúyase mapping.items() por mapping.iteritems()

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

 0
Author: thodnev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-02 18:08:53

Si los valores no son únicos Y pueden 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 necesitas cavar más profundo entonces 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)
 0
Author: mveith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-10 11:06:59

Invierte tu diccionario:

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

print(inversed_dict_["v1"])
 0
Author: Miladiouss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-07 23:37:46

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 agregar a la lista) uno por uno como en la solución imperativa .

Desafortunadamente los valores tienen que ser clasificables, la ordenación es requerida por groupby.

 -1
Author: cjay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:30

Escribí esto con la ayuda de ciclo 'para' y método '.get () 'y cambié el nombre' map 'del diccionario a' map1 'porque' map ' 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
 -1
Author: Taras Voitovych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-05 21:14:02

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()}
 -3
Author: beco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-21 12:53:58

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

Diccionario = {'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'}

 -3
Author: user9918114,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-16 12:23:23

Si los elementos 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
 -5
Author: seiferas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-24 18:17:03