Я хочу зробити щось на кшталт:
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, ви можете зателефонувати set
на дікт, але це повторить весь дікт, щоб створити набір, і це повільно:
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()
Хоча мені подобається відповідь Алекса Мартеллі, мені це не здається пітонічним. Тобто, я вважав, що важливою частиною того, щоб бути пітоніком, є легко зрозуміти. З цією метою <=
зрозуміти непросто.
Хоча це більше персонажів, використання, 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 (мій_вирок).
Це потребує O (Q) + O (D), щоб зробити два набори, а потім (один сподівається!) Тільки O (хв (Q, D)) зробити тест підмножини - якщо, звичайно, припустимо, що Python встановив пошук є O (1) - це найгірший випадок (коли відповідь - правда).
Генераторний розчин hughdbrown (та ін.?) all(k in my_dict for k in queries)
Є найгіршим випадком O (Q).
Ускладнюючі фактори:
(1) петлі в наборі ґаджета робляться зі швидкістю С, тоді як будь-який базований гаджет перебирається через байт-код.
(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
Jason, () не потрібні в 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_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
. Як це насправді працює ?!