2009-06-23 11 views
52

Recibo un diccionario como entrada, y me gustaría devolver un diccionario cuyas claves serán los valores de entrada y cuyo valor serán las teclas de entrada correspondientes. Los valores son únicos.Python: ¿la mejor forma de intercambiar claves con valores en un diccionario?

Por ejemplo, decir que mi entrada es:

a = dict() 
a['one']=1 
a['two']=2 

Me gustaría que mi salida sea:

{1: 'one', 2: 'two'} 

Para aclarar Me gustaría que mi resultado ser el equivalente de los siguientes:

res = dict() 
res[1] = 'one' 
res[2] = 'two' 

¿Alguna forma precisa de Python para lograr esto?

Gracias

+1

Ver http://stackoverflow.com/questions/1087694/how-to-swap-keys-for-values-in-a-dictionary por una cuestión idéntica que tiene una respuesta agradable si estás usando Python 3 –

+0

@Stephen: vea la segunda respuesta más votada, es la misma que la aceptada en la pregunta a la que se vinculó. La multitud prefirió la otra respuesta ... –

+3

Python no es perl, python no es ruby. La legibilidad cuenta Sparse es mejor que denso. Dado esto, todos los métodos de estas respuestas son simplemente malos ™; el que está en la pregunta es la mejor manera de hacerlo. –

Respuesta

77
res = dict((v,k) for k,v in a.iteritems()) 
+0

@nosklo, si lo piensas bien, te darás cuenta de que "hace 24 minutos" era * antes * que "hace 22 minutos". – Armandas

+0

@Armandas: eh, tienes razón. * oculta * – nosklo

+3

Si bien esto parece ser correcto, es realmente bueno agregar una explicación de cómo funciona en lugar de solo el código. – Will

11

res = dict(zip(a.values(), a.keys()))

+4

dict no garantiza que sus valores() y claves() devolver elementos en el mismo orden Además, keys(), values ​​() y zip() devuelven una lista, donde un iterador sería suficiente. – liori

+0

Tienes razón. Tu respuesta es mas eficiente – pkit

+16

@liori: Estás equivocado. dict garantiza que sus valores() y claves() ESTARÁN en el mismo orden, si no modifica la dicción entre llamadas a valores() y teclas(), por supuesto. La documentación indica que aquí: (lea la parte "Nota": http://docs.python.org/library/stdtypes.html#dict.items) "If items(), keys(), values ​​(), iteritems (), iterkeys() y itervalues ​​() se llaman sin modificaciones intermedias en el diccionario, las listas se corresponderán directamente ". – nosklo

18

Usted podría intentar:

d={'one':1,'two':2} 
d2=dict((value,key) for key,value in d.iteritems()) 
d2 
    {'two': 2, 'one': 1} 

Cuidado que un diccionario no puede 'inversa' si

  1. Más de uno comparte clave las mismo valor. Por ejemplo {'one':1,'two':1}. El nuevo diccionario solo puede tener un elemento con la clave 1.
  2. Uno o más de los valores no se puede ajustar. Por ejemplo {'one':[1]}. [1] es un valor válido pero no una clave válida.

Consulte this thread en la lista de correo de python para una discusión sobre el tema.

+0

liori ya proporcionó esa solución, pero gracias –

+0

+1 Agregué una nota sobre valores únicos, gracias –

+0

@Alasdair: Correcto, me confundí con las marcas de tiempo – nosklo

31
In [1]: my_dict = {'x':1, 'y':2, 'z':3} 

In [2]: dict((value, key) for key, value in my_dict.iteritems()) 
Out[2]: {1: 'x', 2: 'y', 3: 'z'} 
+3

No en la pregunta original, solo tengo curiosidad por saber qué sucederá si tuviera valores duplicados en el diccionario original y luego cambie las claves/valores con este método. –

+2

@Andre Miller: toma la última aparición de la clave particular: dict (((1,3), (1,2))) == {1: 2} – balpha

+2

duplicados se sobrescribirán con el último duplicado encontrado. – Christopher

14
new_dict = dict((my_dict[k], k) for k in my_dict) 

o incluso mejor, pero sólo funciona en Python 3:

new_dict = { my_dict[k]: k for k in my_dict} 
+2

En realidad Comprensiones Dict ([PEP 274] (http: // www) .python.org/dev/peps/pep-0274 /)) también funcionan con Python 2.7. – aruseni

49
new_dict = dict (zip(my_dict.values(),my_dict.keys())) 
+3

¿Realmente se garantiza que los valores() y las claves() tengan el mismo orden? –

+1

Consulte la nota de pedido en http://docs.python.org/library/stdtypes.html#dict.items –

+0

sí, en http://www.python.org/dev/peps/pep-3106/ La especificación implica que el orden en el que los elementos son devueltos por .keys(), .values ​​() y .items() es el mismo (al igual que en Python 2.x), porque el orden se deriva todo del dict iterator (que es presumiblemente arbitrario pero estable siempre que no se modifique un dict). pero esta respuesta necesita llamar my_dict dos veces (una para valores, una para claves). tal vez esto no es ideal. – sunqiang

39

Desde Python 2.7 en adelante, incluyendo 3.0 o superior, hay una versión posiblemente más corto, más fácil de leer:

>>> my_dict = {'x':1, 'y':2, 'z':3} 
>>> {v: k for k, v in my_dict.items()} 
{1: 'x', 2: 'y', 3: 'z'} 
4

Sugerencias para una mejora de Javier answe R:

dict(zip(d.values(),d)) 

En lugar de d.keys() puede escribir simplemente d, porque si vas a través de diccionario con un iterador, devolverá las llaves del diccionario correspondiente.

Ej.para este comportamiento:

d = {'a':1,'b':2} 
for k in d: 
k 
'a' 
'b' 
23

Puede hacer uso de dict comprehensions:

res = {v: k for k, v in a.iteritems()} 

Editado: Para Python 3, utilice a.items() en lugar de a.iteritems(). Las discusiones sobre las diferencias entre ellos se pueden encontrar en iteritems in Python en SO.

1

Usando bucle: -

newdict = {} #Will contain reversed key:value pairs. 

for key, value in zip(my_dict.keys(), my_dict.values()): 
    # Operations on key/value can also be performed. 
    newdict[value] = key 
2

Si está utilizando python3, es ligeramente diferente:

res = dict((v,k) for k,v in a.items()) 
1
dict(map(lambda x: x[::-1], YourDict.items())) 

.items() devuelve una lista de tuplas de (key, value). map() pasa por los elementos de la lista y aplica lambda x:[::-1] a cada uno de sus elementos (tupla) para invertirlo, de modo que cada tupla se convierte en (value, key) en la nueva lista escupida fuera del mapa. Finalmente, dict() hace un dict de la nueva lista.

+0

¿Puede explicarme cómo funciona esto? – Will

+0

.items() devuelve una lista de tuplas (clave, valor). map() pasa por los elementos de la lista y aplica 'lambda x: [:: - 1]' a cada uno de sus elementos (tupla) para invertirlo, de modo que cada tupla se convierte (valor, clave) en la nueva lista escindida del mapa . Finalmente, dict() hace un dict de la nueva lista. –

+0

¡Gracias! Edité la respuesta e incluí tu comentario :) – Will

5

Otra forma de ampliar la respuesta de Ilya Prokin es utilizar realmente la función reversed.

dict(map(reversed, my_dict.items())) 

En esencia, su diccionario se repite a través de (usando .items()), donde cada elemento es un par clave/valor, y esos elementos se intercambian con la función reversed. Cuando esto se pasa al constructor dict, los convierte en pares de valor/clave, que es lo que desea.

1

Adición de una solución en el lugar:

>>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'} 
>>> for k in list(d.keys()): 
...  d[d.pop(k)] = k 
... 
>>> d 
{'two': 2, 'one': 1, 'four': 4, 'three': 3} 

En python3, es fundamental que utilice list(d.keys()) PORQUE dict.keys devuelve una vista de las llaves. Si está usando Python2, d.keys() es suficiente.

1

La respuesta principal actual asume que los valores son únicos, lo que no siempre es el caso. ¿Qué pasa si los valores no son únicos? ¡Perderás información! Por ejemplo:

d = {'a':3, 'b': 2, 'c': 2} 
{v:k for k,v in d.iteritems()} 

rendimientos {2: 'b', 3: 'a'}.

La información sobre 'c' se ignoró por completo. Idealmente debería haber sido algo así como {2: ['b','c'], 3: ['a']}. Esto es lo que hace la implementación inferior.

def reverse_non_unique_mapping(d): 
    dinv = {} 
    for k, v in d.iteritems(): 
     if v in dinv: 
      dinv[v].append(k) 
     else: 
      dinv[v] = [k] 
    return dinv 
Cuestiones relacionadas