ฉันต้องการทำสิ่งที่ชอบ:
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
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()
ในขณะที่ฉันชอบคำตอบของ Alex Martelli ฉันไม่ได้ดูเหมือน Pythonic กับฉัน นั่นคือฉันคิดว่าส่วนสำคัญของการเป็น Pythonic ที่เข้าใจได้ง่าย ด้วยเป้าหมาย<=
นั้นไม่ง่ายที่จะเข้าใจ
ในขณะที่มันเป็นตัวละครมากขึ้นการใช้issubset()
ตามคำแนะนำของ Karl Voigtland นั้นเป็นที่เข้าใจได้มากกว่า เนื่องจากวิธีการนั้นสามารถใช้พจนานุกรมเป็นอาร์กิวเมนต์ได้โซลูชันสั้น ๆ ที่เข้าใจได้คือ:
foo = {'foo': 1, 'zip': 2, 'zam': 3, 'bar': 4}
if set(('foo', 'bar')).issubset(foo):
#do stuff
ฉันต้องการใช้{'foo', 'bar'}
แทนset(('foo', 'bar'))
เพราะสั้นกว่า อย่างไรก็ตามมันไม่เข้าใจและฉันคิดว่าเครื่องมือจัดฟันนั้นสับสนง่ายเกินไปว่าเป็นพจนานุกรม
ทางออกของ Alex Martelli 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) ผู้โทรเข้าของแกดเจ็ตใด ๆ อาจสามารถใช้ความรู้เกี่ยวกับความน่าจะเป็นที่จะเกิดความล้มเหลวในการสั่งซื้อรายการเคียวรีตามนั้นขณะที่แกดเจ็ตที่ตั้งค่าไว้จะไม่สามารถควบคุมได้
เช่นเคยหากความเร็วเป็นสิ่งสำคัญการเปรียบเทียบภายใต้สภาพการทำงานเป็นความคิดที่ดี
คุณสามารถใช้ . issset () ได้เช่นกัน
>>> {"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 หรือไม่:
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
ใช้งานได้จริงอย่างไร!