it-swarm.dev

如何在一次通过中检查多个键是否在字典中?

我想做的事情如下:

foo = {'foo':1,'Zip':2,'zam':3,'bar':4}

if ("foo","bar") in foo:
    #do stuff

如何检查'foo'和'bar'是否都在dict foo中?

174
user131465

好吧,你可以这样做:

>>> if all (k in foo for k in ("foo","bar")):
...     print "They're there!"
...
They're there!
302
hughdbrown
if set(("foo", "bar")) <= set(myDict): ...
106
Alex Martelli

3种替代方案的简单基准测试平台。

为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
34
John La Rooy

您不必将左侧包裹在一组中。你可以这样做:

if {'foo', 'bar'} <= set(some_dict):
    pass

这也比all(k in d...)解决方案表现更好。

24
claytonk

使用sets

if set(("foo", "bar")).issubset(foo):
    #do stuff

或者:

if set(("foo", "bar")) <= set(foo):
    #do stuff
21
Karl Voigtland

这个怎么样:

if all(key in foo for key in ["foo","bar"]):
    # do stuff
    pass
7
Greg

虽然我喜欢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')),因为它更短。然而,这不是那么容易理解,我认为括号太容易被混淆为字典。

7
L S

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)任何基于任何小工具的调用者可能能够使用任何失败概率的知识来相应地对查询项进行排序,而基于集合的小工具不允许这样的控制。

与往常一样,如果速度很重要,那么在运行条件下进行基准测试是一个好主意。

4
John Machin

我认为这是最聪明最专业的。

{'key1','key2'} <= my_dict.keys()
3
Shota Tamura

用lambda怎么样?

 if reduce( (lambda x, y: x and foo.has_key(y) ), [ True, "foo", "bar"] ): # do stuff
1
rein

如果你想:

  • 还获取键的值
  • 检查一个以上的dictonary

然后:

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
1
Jochen Ritzel

不是说这不是你没想过的东西,但我发现最简单的东西通常是最好的:

if ("foo" in foo) and ("bar" in foo):
    # do stuff
1
Jason Baker
>>> if 'foo' in foo and 'bar' in foo:
...     print 'yes'
... 
yes

Jason,()在Python中不是必需的。

1
Juanjo Conti

您也可以使用 .issubset()

>>> {"key1", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
True
>>> {"key4", "key2"}.issubset({"key1":1, "key2":2, "key3": 3})
False
>>>
0
Sinan Çetinkaya

就我而言,有两种方法易于理解所有给定的选项。所以我的主要标准是具有非常易读的代码,而不是特别快的代码。为了保持代码可以理解,我更愿意给出可能性:

  • var <= var2.keys()
  • var.issubset(VAR2)

“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
0
PietjePuk