Quiero hacer algo como:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
¿Cómo verifico si tanto 'foo' como 'bar' están en dict foo?
Quiero hacer algo como:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
¿Cómo verifico si tanto 'foo' como 'bar' están en dict foo?
Respuestas:
Bueno, podrías hacer esto:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
setes superior. Como de costumbre ... ¡mídelo! -)
if {"foo", "bar"} <= myDict.keys(): ...
Si todavía estás en Python 2, puedes hacer
if {"foo", "bar"} <= myDict.viewkeys(): ...
Si todavía está en un Python <= 2.6 muy antiguo, puede invocar setel dict, pero iterará sobre todo el dict para construir el conjunto, y eso es lento:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()qué evita el conjunto temporal, por lo que es mucho más rápido. Para mi prueba, tiene aproximadamente la misma velocidad que usar todo cuando la consulta tenía 10 elementos. Sin embargo, se vuelve más lento a medida que la consulta se hace más grande.
if {'foo', 'bar'} <= set(myDict): ...
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
d.viewkeys()que hacer set(q) <= d.viewkeys().
Python 2.7.5Tiene d.keys()método también.
set(q) <= ...
TypeError: can only compare to a set. ¡Lo siento! :))
d.viewkeys() >= set(q). ¡Vine aquí tratando de averiguar por qué importa el orden!
No tiene 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 all(k in d...)solución.
Usando conjuntos :
if set(("foo", "bar")).issubset(foo):
#do stuff
Alternativamente:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)es lo mismo que set(d.keys())(sin la lista intermedia que d.keys()construye)
Qué tal esto:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all.
Creo que este es el más inteligente y decisivo.
{'key1','key2'} <= my_dict.keys()
Si bien me gusta la respuesta de Alex Martelli, no me parece Pythonic. Es decir, pensé que una parte importante de ser Pythonic es ser fácilmente comprensible. Con ese objetivo, <=no es fácil de entender.
Si bien son más personajes, issubset()es más comprensible usar como lo sugiere la respuesta de Karl Voigtland. Dado que ese método puede usar un diccionario como argumento, una solución breve 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 las llaves se confunden demasiado fácilmente como un diccionario.
.issubset(). Creo que estar en la documentación de Python lo hace Pythonic por defecto.
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. Suponga Q = len (consultas) y D = len (my_dict).
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, suponiendo, por supuesto, que la búsqueda de conjuntos de Python es O (1): este es el peor de los casos (cuando la respuesta es verdadera).
La solución generadora de hughdbrown (et al?) all(k in my_dict for k in queries)Es el peor de los casos O (Q).
Factores complicados:
(1) todos los bucles en el gadget basado en conjuntos se realizan a velocidad C, mientras que el gadget basado en cualquier se repite en código de bytes.
(2) La persona que llama del gadget basado en cualquier puede usar cualquier conocimiento de probabilidad de falla 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.
Puede usar .issubset () también
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
¿Qué tal usar lambda?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
En caso de que quieras:
luego:
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
No para sugerir que esto no es algo en lo que no haya pensado, pero creo que lo más simple suele ser lo mejor:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () no son necesarios en Python.
Solo mi opinión sobre esto, hay dos métodos que son fáciles de entender de todas las opciones dadas. Entonces, mi criterio principal es tener un código muy legible, no un código excepcionalmente rápido. Para mantener el código comprensible, prefiero las posibilidades dadas:
El hecho de que "var <= var2.keys ()" se ejecuta más rápido en mis pruebas a continuación, prefiero este.
import timeit
timeit.timeit('var <= var2.keys()', setup='var={"managed_ip", "hostname", "fqdn"}; var2= {"zone": "test-domain1.var23.com", "hostname": "bakje", "api_client_ip": "127.0.0.1", "request_data": "", "request_method": "GET", "request_url": "hvar2p://127.0.0.1:5000/test-domain1.var23.com/bakje", "utc_datetime": "04-Apr-2019 07:01:10", "fqdn": "bakje.test-domain1.var23.com"}; var={"managed_ip", "hostname", "fqdn"}')
0.1745898080000643
timeit.timeit('var.issubset(var2)', setup='var={"managed_ip", "hostname", "fqdn"}; var2= {"zone": "test-domain1.var23.com", "hostname": "bakje", "api_client_ip": "127.0.0.1", "request_data": "", "request_method": "GET", "request_url": "hvar2p://127.0.0.1:5000/test-domain1.var23.com/bakje", "utc_datetime": "04-Apr-2019 07:01:10", "fqdn": "bakje.test-domain1.var23.com"}; var={"managed_ip", "hostname", "fqdn"};')
0.2644960229999924
En el caso de determinar si solo algunas teclas coinciden, esto funciona:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Otra opción más para encontrar si solo algunas teclas coinciden:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
Otra opción para detectar si todas las claves están en un dict:
dict_to_test = { ... } # dict
keys_sought = { "key_sought_1", "key_sought_2", "key_sought_3" } # set
if keys_sought & dict_to_test.keys() == keys_sought:
# yes -- dict_to_test contains all keys in keys_sought
# code_here
pass
>>> ok
{'five': '5', 'two': '2', 'one': '1'}
>>> if ('two' and 'one' and 'five') in ok:
... print "cool"
...
cool
Esto parece funcionar
()serían evaluados primero y dar como resultado True, que luego comprobar si True in ok. ¿Cómo funciona esto realmente?