2012-05-08 19 views
57

tengo:Cómo filtrar claves de diccionario basado en sus valores correspondientes

dictionary = {"foo":12, "bar":2, "jim":4, "bob": 17} 

Quiero iterar sobre este diccionario, pero con los valores en lugar de las teclas, por lo que puede utilizar los valores en otra función.

Por ejemplo, quiero probar qué valores de diccionario son mayores que 6, y luego almacenar sus claves en una lista. Mi código es el siguiente:

list = [] 
for c in dictionary: 
    if c > 6: 
     list.append(dictionary[c]) 
print list 

y luego, en un mundo perfecto, list contaría con todas las claves cuyo valor es mayor que 6. Sin embargo, mi ciclo for solo itera sobre las teclas; Me gustaría cambiar eso a los valores!

Cualquier ayuda es muy apreciada. agradecimiento

+1

El título de esta pregunta debe ser modificado después de lo que realmente quiere lograr (y las respuestas reflejan esta) es obtener las claves de los valores correspondientes en un diccionario para el cual una determinada cláusula es verdadera. Algo así como "Cómo filtrar las claves del diccionario en función de sus valores correspondientes" podría ser una mejor alternativa. – glarrain

Respuesta

81
>>> d = {"foo": 12, "bar": 2, "jim": 4, "bob": 17} 
>>> [k for k, v in d.items() if v > 6] # Use d.iteritems() on python 2.x 
['bob', 'foo'] 

me gustaría actualizar simplemente esta respuesta para exhibir también la solución por @glarrain que me encuentro que tiende a utilizar hoy en día.

[k for k in d if d[k] > 6] 

Esto es completamente compatible cruz y no requiere un cambio confuso de .iteritems (.iteritems evita ahorro de una lista de memoria en Python 2 que se fija en Python 3) para .items.

@ Prof.Falken mencionado una solución a este problema

from six import iteritems 

que fija de manera efectiva los problemas de compatibilidad cruz, sino que requiere para descargar el paquete six

Sin embargo, no estaría de acuerdo plenamente con @glarrain que esta solución es más legible, eso es tema de debate y tal vez solo una preferencia personal, aunque se supone que Python tiene solo 1 forma de hacerlo. En mi opinión, depende de la situación (por ejemplo, puede tener un nombre de diccionario largo que no desea escribir dos veces o quiere dar a los valores un nombre más legible u otro motivo)

Algunos tiempos interesantes :

En Python 2, la segunda solución es más rápida, en Python 3 son casi exactamente iguales en velocidad bruta.


$ python -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k, v in d.items() if v > 6]' 
1000000 loops, best of 3: 0.772 usec per loop 
$ python -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k, v in d.iteritems() if v > 6]' 
1000000 loops, best of 3: 0.508 usec per loop 
$ python -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k in d if d[k] > 6]' 
1000000 loops, best of 3: 0.45 usec per loop 

$ python3 -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k, v in d.items() if v > 6]' 
1000000 loops, best of 3: 1.02 usec per loop 
$ python3 -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k in d if d[k] > 6]' 
1000000 loops, best of 3: 1.02 usec per loop 

Sin embargo, estos son sólo pruebas para pequeños diccionarios, en enormes diccionarios Estoy bastante seguro de que no tener un diccionario de búsqueda de claves (d[k]) haría .items mucho más rápido. Y este parece ser el caso

$ python -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k in d if d[k] > 6]' 
1 loops, best of 3: 1.75 sec per loop 
$ python -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k, v in d.iteritems() if v > 6]' 
1 loops, best of 3: 1.71 sec per loop 
$ python3 -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k in d if d[k] > 6]' 
1 loops, best of 3: 3.08 sec per loop 
$ python3 -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k, v in d.items() if v > 6]' 
1 loops, best of 3: 2.47 sec per loop 
+0

+1. Definitivamente la mejor respuesta en mi humilde opinión. –

+5

Para python 2.x, 'd.iteritems()' sería mejor AFAIK. – hochl

+0

Brillante, ¡gracias! – Hoops

4

¿Qué tal esto:

dictionary = {"foo":12, "bar":2, "jim":4, "bob": 17} 
for val in dictionary.values(): 
    # do something 
+0

Si a OP no le importa, me gustaría eliminarlo mi respuesta. @ jamylak's definitivamente es el camino a seguir. –

36

para obtener sólo los valores, utilice dictionary.values()

Para obtener pares de valores clave, utilice dictionary.items()

10

Use items o iteritems en el diccionario. Algo como:

list = [] 
for k, v in dictionary.iteritems(): 
    if v > 6: 
    list.append(k) 
print list 
2

Depende si desea modificar el diccionario (agregar o quitar elementos) o no. Si no, entonces usted podría intentar:

for value in dictionary.itervalues(): #this returns a generator 
    print "do something with the value" 

Alternativamente si modifica el diccionario que debe iterar sobre una copia de los valores:

for value in dictionary.values(): #this returns a list of values 
    print "do something with the value" 

Si desea ambas claves y valores que puede iterar sobre pares usando dictionary.iteritems() o dictionary.items()

2

Creo que la mejor manera de hacer esto (teniendo en cuenta la migración a Python 3) es

>>> mydict = {'foo': 12, 'bar': 2, 'jim': 4, 'bob': 17} 
>>> [k for k in mydict if mydict[k] > 6] 
['bob', 'foo'] 

El criterio para "mejor" es la legibilidad.

(Negación: mi respuesta se basa en la respuesta de Alex Martelli a otra pregunta https://stackoverflow.com/a/3744713/556413 y @ de jamylak a esta pregunta)

Cuestiones relacionadas