Я хочу сделать что-то вроде:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Как проверить, находятся ли оба слова 'foo' и 'bar' в dict foo?
Я хочу сделать что-то вроде:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Как проверить, находятся ли оба слова 'foo' и 'bar' в dict foo?
Ответы:
Ну, вы могли бы сделать это:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
setлучше. Как обычно ... измерить! -)
if {"foo", "bar"} <= myDict.keys(): ...
Если вы все еще на Python 2, вы можете сделать
if {"foo", "bar"} <= myDict.viewkeys(): ...
Если вы все еще на самом старом Python <= 2.6, вы можете вызвать setdict, но он будет перебирать весь dict для создания набора, и это медленно:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()что избегает временного набора, поэтому гораздо быстрее. Для моего тестирования это примерно та же скорость, что и при использовании всего, когда запрос был 10 элементов. Это становится медленнее, когда запрос становится больше, хотя.
if {'foo', 'bar'} <= set(myDict): ...
Введите свои собственные значения для D и 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()сделать set(q) <= d.viewkeys().
Python 2.7.5есть d.keys()метод тоже.
set(q) <= ...
TypeError: can only compare to a set. Сожалею! :))
d.viewkeys() >= set(q). Я пришел сюда, чтобы выяснить, почему порядок имеет значение!
Вам не нужно оборачивать левую сторону в наборе. Вы можете просто сделать это:
if {'foo', 'bar'} <= set(some_dict):
pass
Это также работает лучше, чем all(k in d...)решение.
Используя наборы :
if set(("foo", "bar")).issubset(foo):
#do stuff
В качестве альтернативы:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)такой же, как set(d.keys())(без промежуточного списка, который d.keys()
Как насчет этого:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all.
Я думаю, что это самый умный и содержательный.
{'key1','key2'} <= my_dict.keys()
Хотя мне нравится ответ Алекса Мартелли, он не кажется мне пифоническим. То есть я думал, что важная часть того, чтобы быть Pythonic, должна быть легко понятной. С этой целью <=не легко понять.
Хотя это больше символов, использование, issubset()как предложено ответом Карла Фойгтланда, более понятно. Поскольку этот метод может использовать словарь в качестве аргумента, короткое, понятное решение:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
Я хотел бы использовать {'foo', 'bar'}вместо set(('foo', 'bar')), потому что это короче. Тем не менее, это не так понятно, и я думаю, что скобки слишком легко спутать как словарь.
.issubset(). Я думаю, что в документации по Python по умолчанию это Pythonic.
Решение Алекса Мартелли set(queries) <= set(my_dict) - самый короткий код, но, возможно, не самый быстрый. Предположим, Q = len (запросы) и D = len (my_dict).
Требуется O (Q) + O (D), чтобы сделать два набора, а затем (можно надеяться!) Только O (min (Q, D)), чтобы выполнить тест подмножества - при условии, конечно, что поиск набора Python O (1) - это наихудший случай (когда ответ True).
Генераторное решение hughdbrown (et al?) all(k in my_dict for k in queries)Является наихудшим вариантом O (Q).
Осложняющие факторы:
(1) все циклы в основанном на множестве гаджете все выполняются на C-скорости, тогда как любое основанное на гаджете зацикливается на байт-коде.
(2) Вызывающий объект любого гаджета на основе может иметь возможность использовать любое знание вероятности сбоя, чтобы упорядочить элементы запроса соответствующим образом, тогда как гаджет на основе набора не допускает такого контроля.
Как всегда, если важна скорость, рекомендуется провести сравнительный анализ в условиях эксплуатации.
Вы можете использовать .issubset () , а также
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
Как насчет использования лямбда?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
Если вы хотите:
затем:
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
Не хочу предполагать, что это не то, о чем вы не подумали, но я считаю, что самая простая вещь, как правило, самая лучшая:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Джейсон, () не нужны в Python.
На мой взгляд, есть два метода, которые легко понять из всех приведенных вариантов. Так что мои главные критерии - это очень читаемый код, а не исключительно быстрый код. Чтобы код был понятен, я предпочитаю использовать следующие возможности:
Тот факт, что "var <= var2.keys ()" выполняется быстрее в моем тестировании ниже, я предпочитаю этот.
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
В случае определения соответствия только некоторых ключей это работает:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Еще один вариант найти, если совпадают только некоторые ключи:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
Еще одна опция для определения, все ли ключи находятся в 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
Это похоже на работу
()что сначала будет оцениваться результат True, а затем проверяться, если True in ok. Как это на самом деле работает ?!