Voglio fare qualcosa del tipo:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Come posso verificare se sia "foo" che "bar" sono in dict foo?
Voglio fare qualcosa del tipo:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Come posso verificare se sia "foo" che "bar" sono in dict foo?
Risposte:
Bene, potresti farlo:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
set
è superiore. Come al solito ... misuralo! -)
if {"foo", "bar"} <= myDict.keys(): ...
Se sei ancora su Python 2, puoi farlo
if {"foo", "bar"} <= myDict.viewkeys(): ...
Se sei ancora su un Python molto vecchio <= 2.6, puoi chiamare set
il dict, ma itererà su tutto il dict per costruire il set, e questo è lento:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()
che evita il set temporaneo, quindi è molto più veloce. Per i miei test ha circa la stessa velocità dell'utilizzo di tutto quando la query era di 10 elementi. Diventa più lento man mano che la query diventa più grande.
if {'foo', 'bar'} <= set(myDict): ...
Inserisci i tuoi valori per D e 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()
fare set(q) <= d.viewkeys()
.
Python 2.7.5
ha d.keys()
anche metodo.
set(q) <= ...
TypeError: can only compare to a set
. Scusa! :))
d.viewkeys() >= set(q)
. Sono venuto qui cercando di scoprire perché l'ordine conta!
Non è necessario avvolgere il lato sinistro in un set. Puoi fare solo questo:
if {'foo', 'bar'} <= set(some_dict):
pass
Anche questo funziona meglio della all(k in d...)
soluzione.
Utilizzando set :
if set(("foo", "bar")).issubset(foo):
#do stuff
In alternativa:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)
è lo stesso di set(d.keys())
(senza l'elenco intermedio che d.keys()
costruisce)
Cosa ne pensi di questo:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all
.
Penso che questo sia il più intelligente e pitonico.
{'key1','key2'} <= my_dict.keys()
Mentre mi piace la risposta di Alex Martelli, non mi sembra Pythonic. Cioè, ho pensato che una parte importante dell'essere Pythonic fosse di essere facilmente comprensibile. Con questo obiettivo, <=
non è facile da capire.
Sebbene siano più personaggi, l'utilizzo issubset()
come suggerito dalla risposta di Karl Voigtland è più comprensibile. Poiché tale metodo può utilizzare un dizionario come argomento, una soluzione breve e comprensibile è:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
Mi piacerebbe usare {'foo', 'bar'}
al posto di set(('foo', 'bar'))
, perché è più corto. Tuttavia, non è così comprensibile e penso che le parentesi graffe siano troppo facilmente confuse come un dizionario.
.issubset()
. Penso che essere nella documentazione di Python lo rende Pythonic per impostazione predefinita.
La soluzione di Alex Martelli set(queries) <= set(my_dict)
è il codice più breve ma potrebbe non essere il più veloce. Assumi Q = len (query) e D = len (my_dict).
Questo richiede O (Q) + O (D) per creare i due set e quindi (uno spera!) Solo O (min (Q, D)) per eseguire il test del sottoinsieme, supponendo ovviamente che Python abbia impostato la ricerca è O (1) - questo è il caso peggiore (quando la risposta è vera).
La soluzione del generatore di hughdbrown (et al?) all(k in my_dict for k in queries)
È il caso peggiore O (Q).
Fattori complicanti:
(1) i loop nel gadget basato su set sono tutti eseguiti a velocità C mentre il gadget qualsiasi basato su loop passa sopra il bytecode.
(2) Il chiamante del gadget basato su qualsiasi potrebbe essere in grado di utilizzare qualsiasi conoscenza della probabilità di errore per ordinare gli elementi della query di conseguenza, mentre il gadget basato su set non consente tale controllo.
Come sempre, se la velocità è importante, l'analisi comparativa in condizioni operative è una buona idea.
È possibile utilizzare .issubset () come pure
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
Che ne dici di usare lambda?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
Nel caso tu voglia:
poi:
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
Non per suggerire che questo non è qualcosa a cui non hai pensato, ma trovo che la cosa più semplice sia di solito la migliore:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () non sono necessari in Python.
Solo la mia opinione su questo, ci sono due metodi che sono facili da capire di tutte le opzioni fornite. Quindi il mio criterio principale è avere un codice molto leggibile, non un codice eccezionalmente veloce. Per mantenere comprensibile il codice, preferisco dare delle possibilità:
Il fatto che "var <= var2.keys ()" venga eseguito più velocemente nei miei test di seguito, preferisco questo.
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
Nel caso di determinare se solo alcune chiavi corrispondono, questo funziona:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Ancora un'altra opzione per trovare se solo alcune chiavi corrispondono:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
Un'altra opzione per rilevare se tutti i tasti sono in 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
Questo sembra funzionare
()
sarebbe stato valutato per primo e si True
sarebbe verificato, il che avrebbe verificato se True in ok
. Come funziona davvero ?!