단일 패스에서 여러 키가 사전에 있는지 어떻게 확인합니까?


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의 대답보다 이것을 더 좋아합니다 (관련없는 임시 목록을 작성하지 않고 단락을 완전히 이용합니다).
Alex Martelli

4
나는 all ()과 any ()를 좋아합니다. 그들은 너무 많은 알고리즘을 훨씬 더 깨끗하게 만듭니다.
hughdbrown

결국이 솔루션을 사용했습니다. 더 큰 데이터 세트에 가장 적합했습니다. 25 또는 30 개의 키를 확인할 때.

4
특히 테스트가 자주 실패하는 경우 단락으로 인해 좋은 솔루션입니다. 당신은 단 한 번 관심의 키 세트를 만들고 여러 번 확인할 수 있습니다하지 않는 한, 그 경우는 set우수하다. 평소와 같이 ... 측정 해보세요!-)
Alex Martelli

나는 "정상적인"방법보다 더 좋아 보일 때마다 이것을 사용한다. 모든 "또는"또는 "또는"또는 "모든"또는 "모든"을 사용할 수 있기 때문에 또한 좋다. 수행하려는 테스트에 따라 k in foo "또는"k in in foo "
Terence Honles

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

여전히 Python 2를 사용하고 있다면 할 수 있습니다

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

당신이 아직도 있다면 정말 오래된 파이썬 <= 2.6, 당신은 호출 할 수 있습니다 setDICT에 있지만 세트를 구축 할 수있는 전체 DICT를 반복 것이고, 그 느린 :

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

좋아 보인다! 내가 싫어하는 유일한 것은 임시 세트를 만들어야하지만 매우 컴팩트하다는 것입니다. 그래서 말해야합니다 ... 세트를 잘 사용하십시오!
Terence Honles

17
파이썬 3에서는 set(("foo","bar")) <= myDict.keys()임시 세트를 피할 수 있으므로 훨씬 빠릅니다. 내 테스트의 경우 쿼리가 10 개 항목 일 때 모두 사용하는 속도와 거의 같습니다. 쿼리가 커질수록 속도가 느려집니다.
John La Rooy

1
내 테스트 중 일부를 답변으로 게시했습니다. stackoverflow.com/questions/1285911/…
John La Rooy

30
if {'foo', 'bar'} <= set(myDict): ...
보리스 라이 히프

11
왜 이것이 작동하는지 궁금해하는 사람은 : 연산자 <=는 use .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
파이썬 2.7은 d.viewkeys()만들어야한다 set(q) <= d.viewkeys().
Martijn Pieters

Python 2.7.5d.keys()역시 방법.
Ivan Kharlamov

3
@IvanKharlamov, 그러나 Python2에서는 호환되는 객체를 반환하지 않습니다set(q) <= ...
John La Rooy

1
내 나쁜, 당신은 절대적으로 자리 잡고 있습니다 : 그것이 반환합니다 TypeError: can only compare to a set. 죄송합니다! :))
Ivan Kharlamov

1
Python 2의 경우 순서를 전환하십시오 d.viewkeys() >= set(q). 주문이 왜 중요한지 알아 보려고 여기에 왔습니다!
Veedrac

34

왼쪽을 세트로 감쌀 필요는 없습니다. 당신은 이것을 할 수 있습니다 :

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

또한 all(k in d...)솔루션 보다 성능이 우수 합니다.


2
이것은 또한 모든 솔루션 (k in d ...) 솔루션보다 우수합니다. 나는 이것을 편집으로 제안했지만, 근거를 기각 하는 것은 주석을 추가하는 것이 낫다 . 그래서 여기에 저것이 있습니다
miraculixx

@miraculixx 코멘트를 추가하는 것이 좋지 않습니다. 관련 정보를 답변으로 편집하고 댓글을 삭제하는 것이 좋습니다.
endolith 2016 년

1
@endolith 동의합니다. 일부 사람들이 거부 한 편집에서 볼 수 있듯이 일부 사람들은 분명히 알지 못합니다. 어쨌든 그것은 메타가 아닌 여기에 대한 토론입니다.
miraculixx

누군가 이것을 설명해 주시겠습니까? {}이 세트를 생성한다는 것을 모았습니다. 그러나 같지 않은 연산자는 어떻게 작동합니까?
Locane

1
@Locane <= 연산자는 첫 번째 세트가 두 번째 세트의 서브 세트인지 테스트합니다. { '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()구성 하는 중간 목록없이) 와 동일
조센 Ritzel

11

이건 어때요:

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

8
실제로, 그것들은 정상적인 단락 동작을 방해하기 때문에 불필요하고 긍정적으로 해롭다 all.
알렉스 마르 텔리

10

나는 이것이 가장 똑똑하고 비둘기라고 생각합니다.

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

9

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')). 그러나 이해할 수 없으며 괄호가 사전처럼 너무 쉽게 혼란스럽게 생각합니다.


2
나는 그것이 의미하는 바를 이해하면 이해할 수 있다고 생각합니다.
Bobort

이것의 문서에 대한 동의어로 .issubset(). 나는 파이썬 문서에 있으면 기본적으로 파이썬으로 만든다고 생각합니다.
ingyhere

4

Alex Martelli의 솔루션 set(queries) <= set(my_dict) 은 가장 짧은 코드이지만 가장 빠를 수는 없습니다. Q = len (쿼리) 및 D = len (my_dict)이라고 가정하십시오.

파이썬이 세트 설정을 가정 할 때 O (Q) + O (D)를 사용하여 두 세트를 만든 다음 O (min (Q, D)) 만 하위 집합 테스트를 수행합니다. is O (1)-최악의 경우입니다 (답이 True 인 경우).

휴드 브라운의 생성자 솔루션 (et al?) all(k in my_dict for k in queries)은 최악의 경우 O (Q)입니다.

복잡한 요소 :
(1) 세트 기반 가제트의 루프는 모두 C- 속도로 수행되는 반면, 모든 기반 가제트는 바이트 코드를 통해 반복됩니다.
(2) 임의의 가젯의 호출자는 그에 따라 쿼리 항목을 주문하는데 실패 할 확률에 대한 임의의 지식을 사용할 수있는 반면, 세트 기반 가젯은 그러한 제어를 허용하지 않을 수있다.

항상 그렇듯이 속도가 중요하다면 운영 조건 하에서 벤치마킹하는 것이 좋습니다.


1
발전기는 내가 시도한 모든 경우에 더 빨랐습니다. stackoverflow.com/questions/1285911/…
John La Rooy

2

.issubset () 도 사용할 수 있습니다

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

1

람다를 사용하는 것은 어떻습니까?

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

2
이 답변은 Python 1.5에서 간단한 변경 (s / True / 1 /)으로 작동하는 기능적으로 올바른 유일한 답변입니다 ...하지만 다른 것은 없습니다. 그리고 True는 시퀀스 arg의 앞쪽에 갇히기보다는 선택적 이니셜 라이저 arg로 더 좋습니다.
John Machin

1

당신이 원하는 경우 :

  • 키의 값도 얻습니다
  • 하나 이상의 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

이것이 당신이 생각하지 않은 것이 아니라는 것을 제안하지는 않지만, 가장 간단한 것이 일반적으로 최고라는 것을 알았습니다.

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

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

Jason은 () 파이썬에서 필요하지 않습니다.


3
그래도 그들은 좋은 스타일일지도 모릅니다. C ++가없는 뇌는 항상 "foo에서 'foo in (foo
and'bar

1
나는 그들이 필요하지 않다는 것을 이해합니다. 나는이 경우 명확성을 추가한다고 생각합니다.
Jason Baker

0

이걸로 가져 가면 주어진 모든 옵션을 쉽게 이해할 수있는 두 가지 방법이 있습니다. 그래서 내 주요 기준은 매우 빠른 코드가 아니라 읽을 수있는 코드가 있습니다. 코드를 이해하기 쉽게하려면 주어진 가능성을 선호합니다.

  • 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에 있는지 여부를 감지하는 또 다른 옵션 :

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'와 'one'과 'five')는 'five'를 반환하므로 실제로는 'five'가 dict에 있는지 확인합니다.
HardQuestions
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.