Eu quero fazer algo como:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Como verifico se 'foo' e 'bar' estão no dict foo?
Eu quero fazer algo como:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Como verifico se 'foo' e 'bar' estão no dict foo?
Respostas:
Bem, você poderia fazer isso:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
set
é superior. Como de costume ... medi-lo!)
if {"foo", "bar"} <= myDict.keys(): ...
Se você ainda está no Python 2, pode fazer
if {"foo", "bar"} <= myDict.viewkeys(): ...
Se você ainda está em um Python realmente antigo <= 2.6, pode chamar set
o dict, mas ele irá percorrer todo o dict para criar o conjunto, e isso é lento:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()
que evita o conjunto temporário, por isso é muito mais rápido. Para os meus testes, é quase a mesma velocidade que usar todos quando a consulta tinha 10 itens. Porém, fica mais lento à medida que a consulta aumenta.
if {'foo', 'bar'} <= set(myDict): ...
Coloque seus próprios valores para 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()
que fazer set(q) <= d.viewkeys()
.
Python 2.7.5
tem d.keys()
método também.
set(q) <= ...
TypeError: can only compare to a set
. Desculpe! :))
d.viewkeys() >= set(q)
. Eu vim aqui tentando descobrir por que o pedido é importante!
Você não precisa envolver o lado esquerdo em um conjunto. Você pode fazer isso:
if {'foo', 'bar'} <= set(some_dict):
pass
Isso também tem um desempenho melhor que a all(k in d...)
solução.
Usando conjuntos :
if set(("foo", "bar")).issubset(foo):
#do stuff
Alternativamente:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)
é o mesmo que set(d.keys())
(sem a lista intermediária que d.keys()
construtos)
Que tal agora:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all
.
Eu acho que este é o mais inteligente e pithonic.
{'key1','key2'} <= my_dict.keys()
Embora eu goste da resposta de Alex Martelli, isso não me parece pitônico. Ou seja, eu pensei que uma parte importante de ser pitônico é ser facilmente compreensível. Com esse objetivo, <=
não é fácil de entender.
Embora haja mais caracteres, usar issubset()
como sugerido pela resposta de Karl Voigtland é mais compreensível. Como esse método pode usar um dicionário como argumento, uma solução curta e compreensível é:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
Eu gostaria de usar {'foo', 'bar'}
no lugar de set(('foo', 'bar'))
, porque é mais curto. No entanto, não é tão compreensível e acho que os aparelhos são muito facilmente confundidos como um dicionário.
.issubset()
. Eu acho que estar na documentação do Python o torna Pythonic por padrão.
A solução de Alex Martelli set(queries) <= set(my_dict)
é o código mais curto, mas pode não ser o mais rápido. Suponha Q = len (consultas) e D = len (my_dict).
Isso leva O (Q) + O (D) para fazer os dois conjuntos e, em seguida (espera-se!), Apenas O (min (Q, D)) para fazer o teste de subconjunto - assumindo, é claro, que o Python configurou a pesquisa é O (1) - este é o pior caso (quando a resposta for Verdadeira).
A solução geradora de hughdbrown (et al?) all(k in my_dict for k in queries)
É o pior caso O (Q).
Fatores complicadores:
(1) os loops no gadget baseado em conjunto são todos executados na velocidade C, enquanto o gadget baseado em qualquer loop é feito através do bytecode.
(2) O chamador do gadget baseado em qualquer um pode ser capaz de usar qualquer conhecimento de probabilidade de falha para solicitar os itens de consulta de acordo, enquanto o gadget baseado em conjunto não permite esse controle.
Como sempre, se a velocidade é importante, o benchmarking em condições operacionais é uma boa ideia.
Você pode usar .issubset () , bem
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
Que tal usar lambda?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
Caso você queira:
então:
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
Não é para sugerir que isso não é algo em que você não tenha pensado, mas acho que a coisa mais simples é geralmente a melhor:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () não é necessário em Python.
Apenas minha opinião sobre isso, existem dois métodos que são fáceis de entender de todas as opções fornecidas. Portanto, meu principal critério é ter um código muito legível, não um código excepcionalmente rápido. Para manter o código compreensível, prefiro as seguintes possibilidades:
O fato de "var <= var2.keys ()" executar mais rápido nos meus testes abaixo, prefiro 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
No caso de determinar se apenas algumas chaves correspondem, isso funciona:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Ainda outra opção para descobrir se apenas algumas chaves correspondem:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
Outra opção para detectar se todas as chaves estão em um ditado:
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
Isso parece funcionar
()
primeiro seria avaliado e resultaria True
, o qual verificaria se True in ok
. Como isso realmente funciona ?!