Diccionario bidireccional en Python

Bidirectional dict o Injective mapping es una estructura de datos muy útil.

Por lo general cuando usamos un diccionario o tabla hash, tenemos un valor asociado a una clave:

>>> d = {1:'uno', 2:'dos'}
>>> d[1]
'uno'

Pero algunas veces también resulta útil indexar por el valor y obtener la clave.

>>> d['uno']
1

Por ejemplo, en un programa tengo un archivo de configuración que contiene un diccionario dónde las claves son strings de 3 caracteres representando un edificio (‘SFE’, ‘GDP’, …) y las claves números de puerto (5007, 5008, …). En algunas partes el programa requiere conocer el edificio a partir del número de puerto y en otras el puerto a partir del edificio.

¿Cómo obtenemos este comportamiento?

Pregunté en StackOverflow y si bien me apuntaron a una implementación, la solución que más me gustó fue esta:

>>> d.update( dict((d[k], k) for k in d))

Así se ve d ahora:

{1: 'uno', 2: 'dos', 'uno': 1, 'dos': 2}

Y podemos efectivamente indexar por clave o por valor:

>>> d[1]
'uno'
>>> d['uno']
1

Advertencias

No se pueden usar objetos mutables

En los diccionarios de Python solo objetos inmutables pueden ser clave de diccionarios, por lo tanto, en nuestro diccionario bidireccional, tanto las claves como los valores deberán serlo.

Actualizaciones

Otra limitación de este enfoque son las desincronizaciones que puede sufrir al modificar el bidict luego de realizar la transformación; hay que tener cuidado!

  • Luego de agregar un nuevo elemento debemos volver a ejecutar la línea mágica para que cree la entrada inversa.
  • No podemos agregar un par que tenga como clave algo que ya existía como valor o que tenga como valor algo que ya existía como clave.
  • Si borramos una entrada, hay que también borrar su inversa.

Conclusión personal

Como les contaba antes, yo estaba usando el diccionario original en un archivo de configuración, por lo que no toco la estructura de datos durante la ejecución del programa, así que esta solución compacta y elegante… como dijo el filósofo: me viene al pelo!

Espero a alguien más le sirva.

Acerca de Juanjo

Mi nombre es Juanjo Conti, vivo en Santa Fe y soy Ingeniero en Sistemas de Información. Mi lenguaje de programación de cabecera es Python; lo uso para trabajar, estudiar y jugar. Como hobby escribí algunos libros.
Esta entrada fue publicada en Aprendiendo Python y etiquetada . Guarda el enlace permanente.
  • http://blog.tordek.com.ar Tordek

    > Advertencias

    > No se pueden usar objetos inmutables.

    Creo que se te escapó un “in” ;)

  • Juan Rodriguez Monti

    Muy buen dato, Juanjo!. Hace un tiempo me ví en una situación donde necesitaba ésto en Python y no lo tenia. Gracias.