Pregunta

Dado un diccionario así:

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

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

inv_map = { 1: 'a', 2: 'b' }
¿Fue útil?

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

Otros consejos

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)

Para hacer esto mientras se preserva el tipo de mapeo (suponiendo que es una dict o una <=> subclase):

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

Intente esto:

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

(Tenga en cuenta que el Python docs en el diccionario de vistas garantizar explícitamente que .keys() y .values() tienen sus elementos en el mismo orden, lo que permite el acercamiento a la obra.)

Alternativamente:

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

o usando python 3.0 dict comprensiones de

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

Otra forma más funcional:

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

Esto amplía la respuesta https://stackoverflow.com/questions/ 483666 / python-reverse-inverse-a-mapping / 485368 # 485368 , que se aplica 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 es limitada, ya 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 dict resultante.

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

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 aquí :

  

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

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

Agregando mis 2 centavos de manera 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 dict grande, tenga en cuenta que esta solución es mucho menos eficiente que la respuesta Python invierte / invierte un mapeo porque se repite items() varias veces.

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

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

O, también podría 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 & Quot; diccionario simétrico & Quot ;:

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). Sin mencionar que puede agregar o eliminar valores de su SymDict tanto como desee, y su diccionario inverso siempre será válido; esto no es cierto si simplemente invierte todo el diccionario una vez.

Uso de zip

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

Se encarga de los no-valores únicos y conserva mucho de la mirada del único caso.

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

Para Python 3.x, reemplazar itervalues con los valores de.Yo no puedo tomar el crédito para este...fue sugerido por el Icono de Jack.

Pruebe esto para python 2.7 / 3.x

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

Por ejemplo, tiene el siguiente diccionario:

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

Y quieres obtenerlo en una forma tan invertida:

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

Primera solución . Para invertir pares clave-valor en su diccionario, utilice 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 del 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 el enfoque revertir la 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]}

La función es simétrica para los valores de la lista de tipos; Las tuplas se convierten en listas al realizar dictado inverso (dictado inverso (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 en 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

Lo haría de esa manera 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á resultados 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 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']}

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 ordenables, la clasificación es requerida por groupby.

No es algo completamente diferente, solo una receta un poco reescrita de Cookbook. Además, está optimizado al retener el método setdefault, en lugar de hacerlo cada vez 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 ejecutarse en CPython 3.x, para 2.x reemplace mapping.items() con mapping.iteritems()

En mi máquina funciona un poco más rápido que otros ejemplos aquí

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 necesita profundizar más que una sola 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)

Invierta su diccionario:

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

print(inversed_dict_["v1"])

Escribí esto con la ayuda del ciclo 'for' y el 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

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

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

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

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

El resultado de reverse_dictionary, debe ser {1: 'a', 2: 'b', 3: 'c'}

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top