¿Cómo puedo comprobar que hay varias claves en un dict en una sola pasada?


Quiero hacer algo como:

foo = {'foo':1,'zip':2,'zam':3,'bar':4}

if ("foo","bar") in foo:
    #do stuff

No estoy seguro de si es posible, pero me gustaría saber. :-)

Author: martineau, 2009-08-17

13 answers

Bueno, podrías hacer esto:

>>> if all (k in foo for k in ("foo","bar")):
...     print "They're there!"
...
They're there!
 272
Author: hughdbrown,
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-08-17 02:18:15
if set(("foo", "bar")) <= set(myDict): ...
 99
Author: Alex Martelli,
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-08-17 02:22:13

Plataforma de benchmarking simple para 3 de las alternativas.

Ponga sus propios valores para D y Q


>>> from timeit import Timer
>>> setup='''from random import randint as R;d=dict((str(R(0,1000000)),R(0,1000000)) for i in range(D));q=dict((str(R(0,1000000)),R(0,1000000)) for i in range(Q));print("looking for %s items in %s"%(len(q),len(d)))'''

>>> Timer('set(q) <= set(d)','D=1000000;Q=100;'+setup).timeit(1)
looking for 100 items in 632499
0.28672504425048828

#This one only works for Python3
>>> Timer('set(q) <= d.keys()','D=1000000;Q=100;'+setup).timeit(1)
looking for 100 items in 632084
2.5987625122070312e-05

>>> Timer('all(k in d for k in q)','D=1000000;Q=100;'+setup).timeit(1)
looking for 100 items in 632219
1.1920928955078125e-05
 32
Author: John La Rooy,
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-10-11 22:51:48

No tienes que envolver el lado izquierdo en un conjunto. Puedes hacer esto:

if {'foo', 'bar'} <= set(some_dict):
    pass

Esto también funciona mejor que la solución all(k in d...).

 22
Author: claytonk,
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-03-13 16:15:47

Usando juegos:

if set(("foo", "bar")).issubset(foo):
    #do stuff

Alternativamente:

if set(("foo", "bar")) <= set(foo):
    #do stuff
 20
Author: Karl Voigtland,
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-08-17 02:31:28

¿qué tal esto:

if all(key in foo for key in ["foo","bar"]):
    # do stuff
    pass
 7
Author: Greg,
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-10-04 08:12:16

Aunque me gusta la respuesta de Alex Martelli, no me parece pitónica. Es decir, pensé que una parte importante de ser pitónico es ser fácilmente comprensible. Con ese objetivo, <= no es fácil de entender.

Aunque son más caracteres, usar issubset() como sugiere la respuesta de Karl Voigtland es más comprensible. Dado que ese método puede usar un diccionario como argumento, una solución corta y comprensible es:

foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}

if set(('foo', 'bar')).issubset(foo):
    #do stuff

Me gustaría usar {'foo', 'bar'} en lugar de set(('foo', 'bar')), porque es más corto. Sin embargo, no es tan comprensible y creo que los frenos son demasiado fácilmente confundidos como un diccionario.

 5
Author: L S,
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-08 16:04:35

La solución de Alex Martelli set(queries) <= set(my_dict) es el código más corto, pero puede no ser el más rápido. Supongamos Q = len (consultas) y D = len(mi_dicto).

Esto toma O(Q) + O (D) para hacer los dos conjuntos, y luego (¡uno espera!) solo O(min(Q,D)) para hacer la prueba de subconjunto assuming asumiendo por supuesto que la búsqueda de conjunto de Python es O(1) this este es el peor caso (cuando la respuesta es Verdadera).

La solución del generador de hughdbrown (et al?) all(k in my_dict for k in queries) es el peor caso O (Q).

Factores que complican:
(1) los bucles en el el gadget basado en set se realiza a velocidad C, mientras que el gadget basado en cualquier está en bucle sobre bytecode.
(2) El autor de la llamada del gadget basado en cualquier puede ser capaz de utilizar cualquier conocimiento de probabilidad de fallo para ordenar los elementos de consulta en consecuencia, mientras que el gadget basado en conjunto no permite tal control.

Como siempre, si la velocidad es importante, la evaluación comparativa en condiciones operativas es una buena idea.

 3
Author: John Machin,
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-08-17 03:28:50

¿Qué tal usar lambda?

 if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
 1
Author: rein,
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-08-17 02:20:29

En caso de que lo desee:

  • también obtenga los valores para las claves
  • compruebe más de un dictonario

Entonces:

from operator import itemgetter
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
keys = ("foo","bar") 
getter = itemgetter(*keys) # returns all values
try:
    values = getter(foo)
except KeyError:
    # not both keys exist
    pass
 1
Author: Jochen Ritzel,
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-08-17 02:25:45

No quiero sugerir que esto no es algo en lo que no hayas pensado, pero encuentro que lo más simple suele ser lo mejor:

if ("foo" in foo) and ("bar" in foo):
    # do stuff
 1
Author: Jason Baker,
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-08-17 02:28:47
>>> if 'foo' in foo and 'bar' in foo:
...     print 'yes'
... 
yes

Jason, () no son necesarios en Python.

 1
Author: Juanjo Conti,
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-08-17 03:22:50
>>> ok
{'five': '5', 'two': '2', 'one': '1'}

>>> if ('two' and 'one' and 'five') in ok:
...   print "cool"
... 
cool

Esto parece funcionar

 -4
Author: Prashanth Gowda,
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-07-14 17:34:03