Je veux faire quelque chose comme:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Comment vérifier si 'foo' et 'bar' sont bien dans dict foo?
Je veux faire quelque chose comme:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Comment vérifier si 'foo' et 'bar' sont bien dans dict foo?
Réponses:
Eh bien, vous pouvez le faire:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
set
est supérieur. Comme d'habitude ... mesurez-le! -)
if {"foo", "bar"} <= myDict.keys(): ...
Si vous êtes toujours sur Python 2, vous pouvez le faire
if {"foo", "bar"} <= myDict.viewkeys(): ...
Si vous êtes toujours sur très ancien Python <= 2.6, vous pouvez faire appel set
au dict, mais il itérera sur tout le dict pour construire l'ensemble, et c'est lent:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()
ce qui évite l'ensemble temporaire, c'est donc beaucoup plus rapide. Pour mes tests, c'est à peu près la même vitesse que l'utilisation de all lorsque la requête était de 10 éléments. Cela devient plus lent à mesure que la requête grossit.
if {'foo', 'bar'} <= set(myDict): ...
Mettez vos propres valeurs pour D et 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()
faire set(q) <= d.viewkeys()
.
Python 2.7.5
a d.keys()
aussi la méthode.
set(q) <= ...
TypeError: can only compare to a set
. Désolé! :))
d.viewkeys() >= set(q)
. Je suis venu ici pour essayer de comprendre pourquoi la commande était importante!
Vous n'avez pas à envelopper le côté gauche dans un ensemble. Vous pouvez simplement faire ceci:
if {'foo', 'bar'} <= set(some_dict):
pass
Cela fonctionne également mieux que la all(k in d...)
solution.
Utilisation d' ensembles :
if set(("foo", "bar")).issubset(foo):
#do stuff
Alternativement:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)
est le même que set(d.keys())
(sans la liste intermédiaire qui d.keys()
construit)
Que dis-tu de ça:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all
.
Je pense que c'est le plus intelligent et le plus pithonique.
{'key1','key2'} <= my_dict.keys()
Bien que j'aime la réponse d'Alex Martelli, elle ne me semble pas pythonique. Autrement dit, je pensais qu'une partie importante d'être Pythonique est d'être facilement compréhensible. Avec cet objectif,<=
n'est pas facile à comprendre.
Bien qu'il s'agisse de plus de caractères, l'utilisation issubset()
comme suggéré par la réponse de Karl Voigtland est plus compréhensible. Puisque cette méthode peut utiliser un dictionnaire comme argument, une solution courte et compréhensible est:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
Je voudrais utiliser {'foo', 'bar'}
à la place de set(('foo', 'bar'))
, car il est plus court. Cependant, ce n'est pas si compréhensible et je pense que les accolades sont trop facilement confondues comme étant un dictionnaire.
.issubset()
. Je pense qu'être dans la documentation Python en fait Pythonic par défaut.
La solution d'Alex Martelli set(queries) <= set(my_dict)
est le code le plus court mais peut-être pas le plus rapide. Supposons Q = len (requêtes) et D = len (my_dict).
Cela prend O (Q) + O (D) pour faire les deux ensembles, puis (on espère!) Seulement O (min (Q, D)) pour faire le test du sous-ensemble - en supposant bien sûr que la recherche de l'ensemble Python est O (1) - c'est le pire des cas (lorsque la réponse est vraie).
La solution de générateur de hughdbrown (et al?) all(k in my_dict for k in queries)
Est le pire des cas O (Q).
Facteurs de complication:
(1) les boucles dans le gadget basé sur l'ensemble sont toutes effectuées à la vitesse C tandis que le gadget basé sur n'importe quelle boucle passe par le bytecode.
(2) L'appelant du gadget à base quelconque peut être en mesure d'utiliser n'importe quelle connaissance de la probabilité d'échec pour ordonner les éléments de requête en conséquence alors que le gadget à base d'ensemble ne permet aucun contrôle de ce type.
Comme toujours, si la vitesse est importante, l'analyse comparative dans des conditions opérationnelles est une bonne idée.
Vous pouvez utiliser .issubset () et
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
Que diriez-vous d'utiliser lambda?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
Si vous souhaitez:
puis:
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
Pour ne pas suggérer que ce n'est pas quelque chose auquel vous n'avez pas pensé, mais je trouve que la chose la plus simple est généralement la meilleure:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () n'est pas nécessaire en Python.
Juste mon avis à ce sujet, il existe deux méthodes faciles à comprendre pour toutes les options données. Donc, mon critère principal est d'avoir un code très lisible, pas un code exceptionnellement rapide. Pour garder le code compréhensible, je préfère les possibilités données:
Le fait que "var <= var2.keys ()" s'exécute plus rapidement dans mes tests ci-dessous, je préfère celui-ci.
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
Dans le cas de déterminer si seules certaines clés correspondent, cela fonctionne:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Encore une autre option pour trouver si seules certaines clés correspondent:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
Une autre option pour détecter si toutes les clés sont dans 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
Cela semble fonctionner
()
serait évalué et qu'il en résulterait True
, ce qui vérifierait ensuite si True in ok
. Comment cela fonctionne-t-il réellement?!