Tôi muốn làm một cái gì đó như:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Làm cách nào để kiểm tra xem cả 'foo' và 'bar' có trong dict foo không?
Tôi muốn làm một cái gì đó như:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Làm cách nào để kiểm tra xem cả 'foo' và 'bar' có trong dict foo không?
Câu trả lời:
Vâng, bạn có thể làm điều này:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
set
là ưu việt. Như thường lệ ... hãy đo nó! -)
if {"foo", "bar"} <= myDict.keys(): ...
Nếu bạn vẫn dùng Python 2, bạn có thể làm
if {"foo", "bar"} <= myDict.viewkeys(): ...
Nếu bạn vẫn còn trên một Python thực sự cũ <= 2.6, bạn có thể gọi set
dict, nhưng nó sẽ lặp lại toàn bộ lệnh để xây dựng tập hợp và điều đó rất chậm:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()
cái nào tránh được bộ tạm thời, vì vậy nhanh hơn nhiều. Đối với thử nghiệm của tôi, nó có cùng tốc độ với việc sử dụng tất cả khi truy vấn là 10 mục. Nó trở nên chậm hơn khi truy vấn trở nên lớn hơn mặc dù.
if {'foo', 'bar'} <= set(myDict): ...
Đặt các giá trị của riêng bạn cho D và 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()
phải thực hiện set(q) <= d.viewkeys()
.
Python 2.7.5
có d.keys()
phương pháp quá.
set(q) <= ...
TypeError: can only compare to a set
. Lấy làm tiếc! :))
d.viewkeys() >= set(q)
. Tôi đến đây để cố gắng tìm hiểu tại sao đơn hàng lại quan trọng!
Bạn không cần phải bọc bên trái trong một bộ. Bạn chỉ có thể làm điều này:
if {'foo', 'bar'} <= set(some_dict):
pass
Điều này cũng thực hiện tốt hơn so với all(k in d...)
giải pháp.
Sử dụng bộ :
if set(("foo", "bar")).issubset(foo):
#do stuff
Cách khác:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)
giống như set(d.keys())
(không có danh sách trung gian d.keys()
xây dựng)
Còn cái này thì sao:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all
.
Tôi nghĩ rằng đây là thông minh nhất và pithonic.
{'key1','key2'} <= my_dict.keys()
Mặc dù tôi thích câu trả lời của Alex Martelli, nhưng nó không giống Pythonic đối với tôi. Đó là, tôi nghĩ rằng một phần quan trọng của việc trở thành Pythonic là dễ hiểu. Với mục tiêu đó, <=
không dễ hiểu.
Mặc dù đó là nhiều ký tự hơn, sử dụng issubset()
theo gợi ý của câu trả lời của Karl Voigtland là dễ hiểu hơn. Vì phương pháp đó có thể sử dụng từ điển làm đối số, nên một giải pháp ngắn gọn, dễ hiểu là:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
Tôi muốn sử dụng {'foo', 'bar'}
thay thế set(('foo', 'bar'))
, vì nó ngắn hơn. Tuy nhiên, điều đó không dễ hiểu và tôi nghĩ rằng niềng răng quá dễ bị nhầm lẫn là một cuốn từ điển.
.issubset()
. Tôi nghĩ rằng trong tài liệu Python làm cho nó Pythonic theo mặc định.
Giải pháp của Alex Martelli set(queries) <= set(my_dict)
là mã ngắn nhất nhưng có thể không phải là nhanh nhất. Giả sử Q = len (truy vấn) và D = len (my_dict).
Điều này cần O (Q) + O (D) để tạo hai bộ và sau đó (một hy vọng!) Chỉ O (min (Q, D)) để thực hiện kiểm tra tập hợp con - tất nhiên giả sử rằng Python thiết lập tra cứu là O (1) - đây là trường hợp xấu nhất (khi câu trả lời là True).
Giải pháp máy phát của hughdbrown (et al?) all(k in my_dict for k in queries)
Là trường hợp xấu nhất O (Q).
Các yếu tố phức tạp:
(1) các vòng lặp trong tiện ích dựa trên tập hợp đều được thực hiện ở tốc độ C trong khi tiện ích dựa trên bất kỳ đang lặp lại qua mã byte.
(2) Người gọi của tiện ích dựa trên bất kỳ có thể có thể sử dụng bất kỳ kiến thức nào về xác suất thất bại để đặt hàng các mục truy vấn phù hợp trong khi tiện ích dựa trên tập hợp không cho phép điều khiển như vậy.
Như mọi khi, nếu tốc độ là quan trọng, điểm chuẩn trong điều kiện hoạt động là một ý tưởng tốt.
Bạn có thể sử dụng .issubset () cũng
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
Làm thế nào về việc sử dụng lambda?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
Trong trường hợp bạn muốn:
sau đó:
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
Không gợi ý rằng đây không phải là điều bạn chưa từng nghĩ tới, nhưng tôi thấy rằng điều đơn giản nhất thường là tốt nhất:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () không cần thiết trong Python.
Chỉ cần tôi thực hiện điều này, có hai phương pháp dễ hiểu về tất cả các tùy chọn đã cho. Vì vậy, tiêu chí chính của tôi là có mã rất dễ đọc, không phải mã đặc biệt nhanh. Để giữ mã dễ hiểu, tôi thích các khả năng nhất định:
Thực tế là "var <= var2.keys ()" thực thi nhanh hơn trong thử nghiệm của tôi dưới đây, tôi thích cái này hơn.
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
Trong trường hợp xác định liệu chỉ một số khóa khớp với nhau, điều này hoạt động:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Một tùy chọn khác để tìm nếu chỉ một số phím khớp:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
Một tùy chọn khác để phát hiện xem tất cả các khóa có trong một lệnh không:
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
Cái này có vẻ hiệu quả
()
sẽ được đánh giá đầu tiên và kết quả True
, sau đó sẽ kiểm tra xem True in ok
. Làm thế nào điều này thực sự hoạt động?!