Saya ingin melakukan sesuatu seperti:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Bagaimana cara saya mengecek apakah 'foo' dan 'bar' keduanya dalam dict foo?
Saya ingin melakukan sesuatu seperti:
foo = {'foo':1,'zip':2,'zam':3,'bar':4}
if ("foo","bar") in foo:
#do stuff
Bagaimana cara saya mengecek apakah 'foo' dan 'bar' keduanya dalam dict foo?
Jawaban:
Nah, Anda bisa melakukan ini:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
setini lebih baik. Seperti biasa ... mengukurnya! -)
if {"foo", "bar"} <= myDict.keys(): ...
Jika Anda masih menggunakan Python 2, Anda bisa melakukannya
if {"foo", "bar"} <= myDict.viewkeys(): ...
Jika Anda masih menggunakan Python yang sangat lama <= 2.6, Anda dapat memanggil setdict, tetapi itu akan beralih ke seluruh dict untuk membangun set, dan itu lambat:
if set(("foo", "bar")) <= set(myDict): ...
set(("foo","bar")) <= myDict.keys()yang menghindari set sementara, jadi jauh lebih cepat. Untuk pengujian saya, kecepatannya hampir sama dengan menggunakan semua ketika kueri adalah 10 item. Semakin lambat karena kueri semakin besar.
if {'foo', 'bar'} <= set(myDict): ...
Masukkan nilai Anda sendiri untuk D dan 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()dibuat set(q) <= d.viewkeys().
Python 2.7.5punya d.keys()metode juga.
set(q) <= ...
TypeError: can only compare to a set. Maaf! :))
d.viewkeys() >= set(q). Saya datang ke sini mencoba mencari tahu mengapa pesanan itu penting!
Anda tidak harus membungkus sisi kiri dalam satu set. Anda bisa melakukan ini:
if {'foo', 'bar'} <= set(some_dict):
pass
Ini juga berkinerja lebih baik daripada all(k in d...)solusinya.
Menggunakan set :
if set(("foo", "bar")).issubset(foo):
#do stuff
Kalau tidak:
if set(("foo", "bar")) <= set(foo):
#do stuff
set(d)adalah sama dengan set(d.keys())(tanpa daftar perantara yang d.keys()membangun)
Bagaimana dengan ini:
if all([key in foo for key in ["foo","bar"]]):
# do stuff
pass
all.
Saya pikir ini adalah yang paling cerdas dan pithonic.
{'key1','key2'} <= my_dict.keys()
Sementara saya suka jawaban Alex Martelli, sepertinya tidak Pythonic bagi saya. Artinya, saya pikir bagian penting dari menjadi Pythonic adalah agar mudah dimengerti. Dengan tujuan itu, <=tidak mudah dipahami.
Meskipun lebih banyak karakter, menggunakan issubset()seperti yang disarankan oleh jawaban Karl Voigtland lebih dimengerti. Karena metode itu dapat menggunakan kamus sebagai argumen, solusi pendek dan mudah dipahami adalah:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
Saya ingin menggunakannya {'foo', 'bar'}sebagai pengganti set(('foo', 'bar')), karena lebih pendek. Namun, itu tidak bisa dimengerti dan saya pikir kawat gigi terlalu mudah dikacaukan sebagai kamus.
.issubset(). Saya pikir berada dalam dokumentasi Python membuatnya menjadi Pythonic secara default.
Solusi Alex Martelli set(queries) <= set(my_dict)adalah kode terpendek tetapi mungkin bukan yang tercepat. Asumsikan Q = len (kueri) dan D = len (my_dict).
Ini membutuhkan O (Q) + O (D) untuk membuat dua set, dan kemudian (satu harapan!) Hanya O (min (Q, D)) untuk melakukan tes subset - dengan asumsi tentu saja Python mengatur pencarian. adalah O (1) - ini adalah kasus terburuk (ketika jawabannya adalah Benar).
Solusi generator hughdbrown (et al?) all(k in my_dict for k in queries)Adalah yang terburuk O (Q).
Faktor-faktor yang rumit:
(1) loop pada gadget berbasis set semua dilakukan pada kecepatan-C sedangkan gadget berbasis apa pun adalah perulangan dengan bytecode.
(2) Penelepon gadget berbasis apa pun mungkin dapat menggunakan pengetahuan tentang kemungkinan kegagalan untuk memesan item permintaan yang sesuai sedangkan gadget berbasis set tidak memungkinkan kontrol seperti itu.
Seperti biasa, jika kecepatan itu penting, pembandingan dengan kondisi operasional adalah ide yang bagus.
Anda dapat menggunakan .issubset () juga
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
Bagaimana kalau menggunakan lambda?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
Jika Anda ingin:
kemudian:
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
Bukan untuk menyarankan bahwa ini bukan sesuatu yang belum Anda pikirkan, tetapi saya menemukan bahwa hal yang paling sederhana biasanya yang terbaik:
if ("foo" in foo) and ("bar" in foo):
# do stuff
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () tidak perlu dalam Python.
Hanya saya ambil ini, ada dua metode yang mudah dimengerti dari semua opsi yang diberikan. Jadi kriteria utama saya adalah memiliki kode yang sangat mudah dibaca, bukan kode yang sangat cepat. Agar kode dapat dimengerti, saya lebih suka memberi kemungkinan:
Fakta bahwa "var <= var2.keys ()" mengeksekusi lebih cepat dalam pengujian saya di bawah ini, saya lebih suka yang ini.
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
Dalam hal menentukan apakah hanya beberapa kunci yang cocok, ini berfungsi:
any_keys_i_seek = ["key1", "key2", "key3"]
if set(my_dict).intersection(any_keys_i_seek):
# code_here
pass
Namun pilihan lain untuk menemukan jika hanya beberapa kunci yang cocok:
any_keys_i_seek = ["key1", "key2", "key3"]
if any_keys_i_seek & my_dict.keys():
# code_here
pass
>>> ok
{'five': '5', 'two': '2', 'one': '1'}
>>> if ('two' and 'one' and 'five') in ok:
... print "cool"
...
cool
Ini sepertinya berhasil
()akan dievaluasi terlebih dahulu dan menghasilkan True, yang kemudian akan memeriksa apakah True in ok. Bagaimana cara kerjanya?