【发布时间】:2010-11-20 03:09:14
【问题描述】:
我想做这样的事情:
foo = {
'foo': 1,
'zip': 2,
'zam': 3,
'bar': 4
}
if ("foo", "bar") in foo:
#do stuff
如何检查foo 和bar 是否都在字典foo 中?
【问题讨论】:
标签: python dictionary
我想做这样的事情:
foo = {
'foo': 1,
'zip': 2,
'zam': 3,
'bar': 4
}
if ("foo", "bar") in foo:
#do stuff
如何检查foo 和bar 是否都在字典foo 中?
【问题讨论】:
标签: python dictionary
这应该可行:
if all(key in foo for key in ["foo","bar"]):
# do stuff
pass
提示:
在all() 中使用方括号进行列表理解:
if all([key in foo for key in ["foo","bar"]]):
不仅没有必要,而且是有害的,因为它们会阻碍all() 的正常短路行为。
【讨论】:
又短又甜
{"key1", "key2"} <= {*dict_name}
【讨论】:
检查字典中是否存在所有键:
{'key_1', 'key_2', 'key_3'} <= set(my_dict)
检查字典中是否存在一个或多个键:
{'key_1', 'key_2', 'key_3'} & set(my_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:
# True -- dict_to_test contains all keys in keys_sought
# code_here
pass
【讨论】:
在确定是否只有某些键匹配的情况下,这是有效的:
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
【讨论】:
if {"foo", "bar"} <= myDict.keys(): ...
如果你还在使用 Python 2,你可以这样做
if {"foo", "bar"} <= myDict.viewkeys(): ...
如果您仍然使用真正旧 Python set,但它会遍历整个 dict 来构建集合,这就是慢:
if set(("foo", "bar")) <= set(myDict): ...
【讨论】:
set(("foo","bar")) <= myDict.keys(),它避免了临时设置,因此速度更快。对于我的测试,当查询为 10 个项目时,它与使用 all 的速度大致相同。但随着查询变大,它会变慢。
if {'foo', 'bar'} <= set(myDict): ...
这只是我的看法,有两种方法很容易理解所有给定的选项。所以我的主要标准是有非常可读的代码,而不是特别快的代码。为了使代码易于理解,我更喜欢给出可能性:
“var
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
【讨论】:
你也可以使用.issubset()
>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
【讨论】:
我认为这是最聪明和最简单的。
{'key1','key2'} <= my_dict.keys()
【讨论】:
虽然我喜欢 Alex Martelli 的回答,但在我看来它并不像 Pythonic。也就是说,我认为 Pythonic 的一个重要部分是易于理解。有了这个目标,<= 就不容易理解了。
虽然字符更多,但按照 Karl Voigtland 的回答建议使用 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。
您不必将左侧包裹在一组中。你可以这样做:
if {'foo', 'bar'} <= set(some_dict):
pass
这也比all(k in d...) 解决方案执行得更好。
【讨论】:
>>> ok
{'five': '5', 'two': '2', 'one': '1'}
>>> if ('two' and 'one' and 'five') in ok:
... print "cool"
...
cool
这似乎有效
【讨论】:
() 将首先被评估并产生True,然后检查True in ok。这实际上是如何工作的?!
输入你自己的 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)。我来这里是为了弄清楚为什么订单很重要!
Alex Martelli 的解决方案set(queries) <= set(my_dict) 是最短的代码,但可能不是最快的。假设 Q = len(queries) 和 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) any-based gadget 的调用者可能能够使用任何关于失败概率的知识来相应地对查询项进行排序,而基于 set 的 gadget 不允许这样的控制。
与往常一样,如果速度很重要,那么在操作条件下进行基准测试是个好主意。
【讨论】:
>>> if 'foo' in foo and 'bar' in foo:
... print 'yes'
...
yes
Jason, () 在 Python 中不是必需的。
【讨论】:
使用 sets:
if set(("foo", "bar")).issubset(foo):
#do stuff
或者:
if set(("foo", "bar")) <= set(foo):
#do stuff
【讨论】:
set(d) 与set(d.keys()) 相同(没有d.keys() 构造的中间列表)
并不是说这不是你没有想到的事情,但我发现最简单的事情通常是最好的:
if ("foo" in foo) and ("bar" in foo):
# 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
【讨论】:
使用 lambda 怎么样?
if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
【讨论】:
好吧,你可以这样做:
>>> if all (k in foo for k in ("foo","bar")):
... print "They're there!"
...
They're there!
【讨论】:
set 更好。像往常一样...测量它!-)