Chcę zrobić coś takiego:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Jak sprawdzić, czy zarówno „foo”, jak i „bar” są w dict foo?
Chcę zrobić coś takiego:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Jak sprawdzić, czy zarówno „foo”, jak i „bar” są w dict foo?
Odpowiedzi:
Cóż, możesz to zrobić:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
set
to przypadku jest lepszy. Jak zwykle ... zmierzyć to! -)
if {"foo", "bar"} <= myDict.keys(): ...
Jeśli nadal korzystasz z Python 2, możesz to zrobić
if {"foo", "bar"} <= myDict.viewkeys(): ...
Jeśli nadal używasz naprawdę starego Pythona <= 2.6, możesz wywołać set
dyktę, ale będzie on powtarzał się przez cały dykt, aby zbudować zestaw, a to wolno:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()
który unika zestawu tymczasowego, więc jest znacznie szybszy. W moich testach jest to mniej więcej taka sama prędkość, jak w przypadku użycia wszystkich, gdy zapytanie zawierało 10 elementów. Jednak staje się wolniejszy, gdy zapytanie staje się większe.
if {'foo', 'bar'} <= set(myDict): ...
Wprowadź własne wartości dla D i 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()
zrobić set(q) <= d.viewkeys()
.
Python 2.7.5
ma d.keys()
też metodę.
set(q) <= ...
TypeError: can only compare to a set
. Przepraszam! :))
d.viewkeys() >= set(q)
. Przybyłem tutaj, aby dowiedzieć się, dlaczego zamówienie ma znaczenie!
Nie musisz owijać lewej strony w zestaw. Możesz po prostu to zrobić:
if {'foo', 'bar'} <= set(some_dict):
pass
Działa to również lepiej niż all(k in d...)
rozwiązanie.
Korzystanie z zestawów :
if set(("foo", "bar")).issubset(foo):
#do stuff
Alternatywnie:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)
jest taki sam jak set(d.keys())
(bez d.keys()
konstruowanej listy pośredniej )
Co powiesz na to:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all
.
Myślę, że jest to najmądrzejszy i pithonic.
{'key1','key2'} <= my_dict.keys()
Chociaż podoba mi się odpowiedź Alexa Martellego, nie wydaje mi się ona pytoniczna. To znaczy, myślałem, że ważną częścią bycia Pythonem jest łatwość zrozumienia. W tym celu<=
nie jest łatwo zrozumieć.
Chociaż jest więcej postaci, używanie issubset()
zgodnie z sugestią Karla Voigtlanda jest bardziej zrozumiałe. Ponieważ ta metoda może wykorzystywać słownik jako argument, krótkie, zrozumiałe rozwiązanie to:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
Chciałbym użyć {'foo', 'bar'}
zamiast set(('foo', 'bar'))
, ponieważ jest krótszy. Nie jest to jednak tak zrozumiałe i myślę, że nawiasy klamrowe są zbyt łatwo mylone jako słownik.
.issubset()
. Myślę, że obecność w dokumentacji Pythona domyślnie sprawia, że jest to język Python.
Rozwiązanie Alexa Martellego set(queries) <= set(my_dict)
jest najkrótszym kodem, ale może nie być najszybszym. Załóżmy, że Q = len (zapytania) i D = len (mój_dykt).
To zajmuje O (Q) + O (D), aby utworzyć dwa zestawy, a następnie (jeden ma nadzieję!) Tylko O (min (Q, D)), aby wykonać test podzestawu - zakładając oczywiście, że wyszukiwanie zestawu Python to O (1) - jest to najgorszy przypadek (gdy odpowiedź brzmi Prawda).
Generatorowym rozwiązaniem hughdbrown (i in.?) all(k in my_dict for k in queries)
Jest najgorszy przypadek O (Q).
Czynniki komplikujące:
(1) wszystkie pętle w gadżecie opartym na zestawie są wykonywane z prędkością C, podczas gdy gadżet oparty na dowolnym zestawie zapętla się po kodzie bajtowym.
(2) Osoba wywołująca dowolny gadżet może być w stanie wykorzystać dowolną wiedzę o prawdopodobieństwie niezamawiania odpowiednio elementów zapytania, natomiast gadżet oparty na zestawie nie pozwala na taką kontrolę.
Jak zawsze, jeśli prędkość jest ważna, dobrym pomysłem jest przeprowadzenie testów porównawczych w warunkach operacyjnych.
Można użyć .issubset () , jak również
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
A może skorzystasz z lambda?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
Jeśli chcesz:
następnie:
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
Nie sugerując, że nie jest to coś, o czym nie pomyślałeś, ale uważam, że najprostsza rzecz jest zwykle najlepsza:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () nie są potrzebne w Pythonie.
Po prostu moje zdanie na ten temat, istnieją dwie metody, które są łatwe do zrozumienia dla wszystkich podanych opcji. Więc moje główne kryteria to bardzo czytelny kod, a nie wyjątkowo szybki kod. Aby kod był zrozumiały, wolę dawać możliwości:
Fakt, że „var <= var2.keys ()” działa szybciej w moich testach poniżej, wolę ten.
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
W przypadku ustalenia, czy tylko niektóre klucze pasują, działa to:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Jeszcze jedna opcja, aby sprawdzić, czy pasują tylko niektóre klucze:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
Inna opcja wykrywania, czy wszystkie klucze są w nagraniu:
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
To wydaje się działać
()
że zostanie najpierw oceniony i wynik True
, który następnie sprawdzi, czy True in ok
. Jak to właściwie działa ?!