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

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

我想做类似的事情:

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

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

如何检查dict foo中是否同时包含“ foo”和“ bar”?

I want to do something like:

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

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

How do I check whether both foo and bar are in dict foo?


回答 0

好吧,你可以这样做:

>>> if all (k in foo for k in ("foo","bar")):
...     print "They're there!"
...
They're there!

Well, you could do this:

>>> if all (k in foo for k in ("foo","bar")):
...     print "They're there!"
...
They're there!

回答 1

if {"foo", "bar"} <= myDict.keys(): ...

如果您仍在使用Python 2,则可以执行

if {"foo", "bar"} <= myDict.viewkeys(): ...

如果您仍然使用的旧版本<= 2.6的Python,则可以调用setdict,但是它将遍历整个dict以构建集合,这很慢:

if set(("foo", "bar")) <= set(myDict): ...
if {"foo", "bar"} <= myDict.keys(): ...

If you’re still on Python 2, you can do

if {"foo", "bar"} <= myDict.viewkeys(): ...

If you’re still on a really old Python <= 2.6, you can call set on the dict, but it’ll iterate over the whole dict to build the set, and that’s slow:

if set(("foo", "bar")) <= set(myDict): ...

回答 2

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

Simple benchmarking rig for 3 of the alternatives.

Put in your own values for D and 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

回答 3

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

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

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

You don’t have to wrap the left side in a set. You can just do this:

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

This also performs better than the all(k in d...) solution.


回答 4

使用

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

或者:

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

Using sets:

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

Alternatively:

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

回答 5

这个怎么样:

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

How about this:

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

回答 6

我认为这是最明智的选择。

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

I think this is the smartest and pithonic.

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

回答 7

虽然我喜欢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')),因为它更短。但是,这不是很容易理解,我认为花括号像字典一样容易被混淆。

While I like Alex Martelli’s answer, it doesn’t seem Pythonic to me. That is, I thought an important part of being Pythonic is to be easily understandable. With that goal, <= isn’t easy to understand.

While it’s more characters, using issubset() as suggested by Karl Voigtland’s answer is more understandable. Since that method can use a dictionary as an argument, a short, understandable solution is:

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

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

I’d like to use {'foo', 'bar'} in place of set(('foo', 'bar')), because it’s shorter. However, it’s not that understandable and I think the braces are too easily confused as being a dictionary.


回答 8

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时)。

休格布朗(et al?)的生成器解all(k in my_dict for k in queries)为最坏情况O(Q)。

复杂因素:
(1)基于集合的小工具中的循环全部以C速度完成,而基于Any的小工具则在字节码上循环。
(2)基于任何内容的小工具的调用者都可以使用任何失败概率的知识来对查询项目进行相应的排序,而基于集合的小工具则不允许这样的控制。

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

Alex Martelli’s solution set(queries) <= set(my_dict) is the shortest code but may not be the fastest. Assume Q = len(queries) and D = len(my_dict).

This takes O(Q) + O(D) to make the two sets, and then (one hopes!) only O(min(Q,D)) to do the subset test — assuming of course that Python set look-up is O(1) — this is worst case (when the answer is True).

The generator solution of hughdbrown (et al?) all(k in my_dict for k in queries) is worst-case O(Q).

Complicating factors:
(1) the loops in the set-based gadget are all done at C-speed whereas the any-based gadget is looping over bytecode.
(2) The caller of the any-based gadget may be able to use any knowledge of probability of failure to order the query items accordingly whereas the set-based gadget allows no such control.

As always, if speed is important, benchmarking under operational conditions is a good idea.


回答 9

您可以使用.issubset()以及

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

You can use .issubset() as well

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

回答 10

使用lambda怎么样?

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

How about using lambda?

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

回答 11

如果您想:

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

然后:

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

In case you want to:

  • also get the values for the keys
  • check more than one dictonary

then:

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

回答 12

并不是说这不是您没有想到的事情,但是我发现最简单的事情通常是最好的:

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

Not to suggest that this isn’t something that you haven’t thought of, but I find that the simplest thing is usually the best:

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

回答 13

>>> if 'foo' in foo and 'bar' in foo:
...     print 'yes'
... 
yes

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

>>> if 'foo' in foo and 'bar' in foo:
...     print 'yes'
... 
yes

Jason, () aren’t necessary in Python.


回答 14

就我的观点而言,所有给定的选项都有两种易于理解的方法。因此,我的主要标准是具有非常易读的代码,而不是非常快速的代码。为了使代码易于理解,我更喜欢给定可能性:

  • 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

Just my take on this, there are two methods that are easy to understand of all the given options. So my main criteria is have very readable code, not exceptionally fast code. To keep code understandable, i prefer to given possibilities:

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

The fact that “var <= var2.keys()” executes faster in my testing below, i prefer this one.

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

回答 15

在确定是否只有某些键匹配的情况下,这可行:

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

In the case of determining whether only some keys match, this works:

any_keys_i_seek = ["key1", "key2", "key3"]

if set(my_dict).intersection(any_keys_i_seek):
    # code_here
    pass

Yet another option to find if only some keys match:

any_keys_i_seek = ["key1", "key2", "key3"]

if any_keys_i_seek & my_dict.keys():
    # code_here
    pass

回答 16

用于检测所有键是否都在字典中的另一个选项:

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

Another option for detecting whether all keys are in a 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

回答 17

>>> ok
{'five': '5', 'two': '2', 'one': '1'}

>>> if ('two' and 'one' and 'five') in ok:
...   print "cool"
... 
cool

这似乎有效

>>> ok
{'five': '5', 'two': '2', 'one': '1'}

>>> if ('two' and 'one' and 'five') in ok:
...   print "cool"
... 
cool

This seems to work