1回のパスで複数のキーが辞書にあることを確認するにはどうすればよいですか?


218

私は次のようなことをしたいです:

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

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

「foo」と「bar」の両方がdict fooにあるかどうかを確認するにはどうすればよいですか?

回答:


363

さて、あなたはこれを行うことができます:

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

10
+ 1、Gregの答えよりも簡潔で速く(無関係な一時リストを作成せず、短絡を完全に利用しないため)、私はこれがGregの答えよりも好きです。
Alex Martelli、

4
all()とany()が大好きです。それらは非常に多くのアルゴリズムをとてもきれいにします。
hughdbrown 09

最終的に私はこのソリューションを使用することになりました。これは、より大きなデータセットに最適です。たとえば25または30のキーをチェックする場合。

4
短絡のおかげで、特にテストが頻繁に失敗する場合は、これは良い解決策です。目的のキーのセットを1回だけ作成して何度も確認できる場合を除いて、その場合の方setが優れています。いつものように...それを測定してください!-)
Alex Martelli

「通常」の方法よりも見栄えがよく、すべてのandとorのいずれかでこれを使用します...「all」または「any」のいずれかを使用できるため、これもまた便利です。実行しようとしているテストに応じて、k in foo "または" k not in foo "
Terence Honles

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

まだPython 2を使用している場合は、次のことができます

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

まだ2.6未満の非常に古いPythonを使用している場合はset、dictを呼び出すことができますが、dict全体を繰り返し処理してセットを構築するので、処理が遅くなります。

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

いいね!私が気に入らない唯一のことは、一時的なセットを作成する必要があることですが、それは非常にコンパクトです。だから私は言わなければなりません...セットの素敵な使い方!
Terence Honles、2009

17
Python 3 set(("foo","bar")) <= myDict.keys()では、一時的なセットを回避できるため、はるかに高速です。私のテストでは、クエリが10アイテムのときにすべてを使用した場合とほぼ同じ速度です。ただし、クエリが大きくなるほど遅くなります。
John La Rooy、2009年

1
いくつかのテストを回答として投稿しました。stackoverflow.com/questions/1285911/...
ジョン・ラRooy

30
if {'foo', 'bar'} <= set(myDict): ...
Boris Raicheff 2014

11
なぜこれが機能するのか疑問に思う方のために:演算子<=は.set issubset()メソッドを使用するのと同じです:docs.python.org/3/library/stdtypes.html#set-types-set-frozenset
edepe

41

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

4
Python 2.7でd.viewkeys()作成する必要がありset(q) <= d.viewkeys()ます。
Martijn Pieters

Python 2.7.5持ちd.keys()すぎ方法を。
Ivan Kharlamov 2013年

3
@IvanKharlamov、ただしPython2では、互換性のあるオブジェクトは返されませんset(q) <= ...
John La Rooy

1
私の悪いことに、あなたは絶対にスポットを当てています:それは戻りますTypeError: can only compare to a set。ごめんなさい!:))
Ivan Kharlamov 2013年

1
Python 2の場合、順序を入れ替えますd.viewkeys() >= set(q)。順序が重要な理由を見つけるためにここに来ました!
Veedrac 14

34

左側をセットで囲む必要はありません。あなたはこれを行うことができます:

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

これは、all(k in d...)ソリューションよりもパフォーマンスが優れています。


2
これは、all(k in d ...)ソリューションよりもパフォーマンスが優れています。私はこれを編集として提案しましたが、コメントを追加した方いいという理由で拒否されました。だからここで私はまさにそれをやっています
miraculixx

@miraculixxコメントを追加するのは得策ではありません。関連情報を回答に編集し、コメントを削除することをお勧めします。
内部石2016年

1
@endolith同意します。拒否された編集で私が最初に行ったように、一部の人々は明らかにそうではありません。とにかく、それはここではなくメタについての議論です。
miraculixx 2016年

誰かがこれを説明できますか?{}がセットを作成することを収集しましたが、以下の演算子はここでどのように機能していますか?
Locane 2016年

1
@Locane <=演算子は、最初のセットが2番目のセットのサブセットであるかどうかをテストします。{'foo'、 'bar'}。issubset(somedict)を実行することもできます。セット方法論のドキュメントはここにあります: docs.python.org/2/library/sets.html
Meow

24

セットの使用:

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

または:

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

2
私の答えで使用したset(d)はset(d.keys())と同じですが、高速で短く、スタイル的に好ましいと言えます。
Alex Martelli、

set(d)と同じですset(d.keys())d.keys()構築する中間リストなし)
Jochen Ritzel

11

これはどう:

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

8
実際、これらは、の通常の短絡動作を妨げるので、不必要なだけでなく、確実に有害ですall
Alex Martelli、

10

これは最も賢くてピトニックだと思います。

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

9

私はAlex Martelliの答えが好きですが、私にはPythonicには思えません。つまり、Pythonicであることの重要な部分は、簡単に理解できることだと思いました。その目標で<=は、理解するのは簡単ではありません。

それはより多くのキャラクターですが、issubset()カール・フォイトランドの答えが示唆するように使用する方が理解しやすいです。そのメソッドは、引数としてディクショナリを使用できるため、短く理解できる解決策は次のとおりです。

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

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

の方が短いので{'foo', 'bar'}、の代わりに使用したいと思いset(('foo', 'bar'))ます。しかし、それはそれほど理解できませんし、中括弧は辞書であると簡単に混同されると思います。


2
それが何を意味するのか理解すれば理解できると思います。
2017年

それはだドキュメントでの同義語として.issubset()。Pythonのドキュメントにあると、デフォルトでPythonicになると思います。
ingyhere

4

Alex Martelliのソリューション set(queries) <= set(my_dict)は最短のコードですが、最速ではない場合があります。Q = len(queries)およびD = len(my_dict)と仮定します。

これはO(Q)+ O(D)を使用して2つのセットを作成し、次に(1つは期待しています!)O(min(Q、D))だけを使用してサブセットテストを実行します-もちろん、Pythonがルックアップを設定するとしますis O(1)-これは最悪のケースです(答えがTrueの場合)。

hughdbrown(et al?)のジェネレーターソリューションall(k in my_dict for k in queries)は、最悪の場合のO(Q)です。

複雑な要因:
(1)セットベースのガジェットのループはすべてC速度で実行されますが、任意ベースのガジェットはバイトコード上でループします。
(2)セットベースのガジェットはそのような制御を許可しないのに対し、任意ベースのガジェットの呼び出し元は、クエリ項目の順序付けに失敗する確率の知識を使用できる場合があります。

いつものように、速度が重要である場合、運用条件下でのベンチマークは良い考えです。


1
ジェネレーターは私が試したすべてのケースでより高速でした。stackoverflow.com/questions/1285911/...
ジョン・ラRooy


1

ラムダを使用するのはどうですか?

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

2
この答えは、単純な変更(s / True / 1 /)を使用してPython 1.5で機能する唯一の機能的に正しいものです...しかし、それ以外には何も起こりません。そして、Truethingyは、オプションの初期化引数として、シーケンス引数の前に詰め込むよりも優れています。
John Machin、

1

あなたがしたい場合:

  • キーの値も取得します
  • 複数の独裁者をチェック

次に:

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

これがあなたが考えたことのないものではないということを示唆するわけではありませんが、私は通常、最も単純なものが最善であると思います:

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

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

Jason、()はPythonでは必要ありません。


3
それでもそれらは良いスタイルかもしれません...それらがないと、私のC ++に追加された頭脳は、「もしfoo in(foo and 'bar')in foo:」として解釈されるのかといつも疑問に思います
Jeremy Friesner

1
必要ないことを理解しています。この場合、彼らは明快さを加えていると感じます。
Jason Baker、

0

私の考えでは、与えられたすべてのオプションを理解しやすい2つの方法があります。したがって、私の主な基準は、非常に読みやすいコードであり、非常に高速なコードではありません。コードを理解しやすくするために、私は与えられた可能性を好む:

  • 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

一部のキーのみが一致するかどうかを判断する場合、これは機能します。

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

0

すべてのキーが辞書にあるかどうかを検出する別のオプション:

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

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

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

これはうまくいくようです


これは巧妙で、自分で試してみるまで機能しないと確信していました。私が疑わ()最初に評価し、その結果にされるだろうTrue、その後かどうかを確認思われます、True in ok。これは実際にはどのように機能しますか?
durden2.0

7
( 'two' and 'one' and 'five')は 'five'を返すので、実際には 'five'が
辞書
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.