특정 키만 포함하도록 필터 dict?


496

나는 dict많은 항목을 가지고 있습니다. 나는 그들 중 일부에만 관심이 있습니다. 다른 모든 것을 정리하는 쉬운 방법이 있습니까?


어떤 유형의 키 (정수? 문자열? 날짜? 임의의 객체?)를 말하고 어떤 키가 들어 있는지 또는 나가는 지 확인하기위한 간단한 (문자열, 정규식, 목록 멤버쉽 또는 숫자 부등식) 테스트가 있는지 확인하는 것이 좋습니다. 또는 임의의 함수를 호출하여이를 결정해야합니다.
smci

@smci 문자열 키. 내가 다른 것을 사용할 수 있다고 생각조차하지 않았다. 나는 오랫동안 JS와 PHP로 코딩 해왔다.
mpen

답변:


656

새로운 dict 구성하기 :

dict_you_want = { your_key: old_dict[your_key] for your_key in your_keys }

사전 이해를 사용합니다.

부족한 버전을 사용하는 경우 (예 : Python 2.6 및 이전 버전) 확인하십시오 dict((your_key, old_dict[your_key]) for ...). 더 나쁘지만 동일합니다.

이것은 jnnnnn의 버전과 달리 old_dict모든 크기의 안정적인 성능 (your_keys 수에 따라 다름)을 갖습니다 . 속도와 메모리면에서 모두. 이것은 생성자 표현식이므로 한 번에 하나의 항목을 처리하며 old_dict의 모든 항목을 살펴 보지는 않습니다.

전체 위치 제거 :

unwanted = set(keys) - set(your_dict)
for unwanted_key in unwanted: del your_dict[unwanted_key]

8
"당신이 부족한 버전을 사용하는 경우 사전 이해를 사용합니다"== 버전 <= 2.6
getekha

8
filer 키 중 하나가 old_dict에 없으면 KeyError를 발생시킵니다. 내가 제안 {K를 : k에 대한 D [K]를 필터 D에서 K 경우}
피터 깁슨

1
@PeterGibson 예, 그것이 요구 사항의 일부라면 그것에 대해 뭔가 를해야합니다. 키를 자동으로 삭제하거나 기본값을 추가하는 등의 작업은 수행중인 작업에 따라 다릅니다. 접근 방식이 잘못된 사용 사례가 많이 있습니다. 누락 된 키가 old_dict다른 곳에서 버그 를 나타내는 곳도 많이 있으며, 이 경우 자동으로 잘못된 결과에 대한 오류를 선호합니다.

@delnan, 또한 "if k in d"추가는 d가 크면 속도가 느려집니다. 언급 할 가치가 있다고 생각했습니다.
Peter Gibson

7
@PeterGibson 사전 검색은 O (1)이 아닙니다.

130

약간 더 우아한 받아쓰기 이해 :

foodict = {k: v for k, v in mydict.items() if k.startswith('foo')}

공감. 나는 이것과 비슷한 대답을 추가하려고 생각했습니다. 그래도 호기심 때문에, dict의 k에 대한 {k : dict [k]가 아닌 dict.items () ...의 {k : v에 대한 k, v ...} 성능 차이가있는 이유는 무엇입니까?
Hart Simha 2016 년

4
내 자신의 질문에 대답했습니다. dict ...}의 k에 대한 {k : dict [k]는 26 개 항목의 사전으로 적어도 Python 2.7.6에서 약 20-25 % 빠릅니다 (timeit (..., setup = "d = 필터링되는 항목 수에 따라 {chr (x + 97) : x + 1 (x in range (26)} "")) (자음 키를 필터링하면 모음 키를 필터링하는 것보다 빠릅니다. 더 적은 품목). 사전 크기가 커질수록 성능의 차이가 덜 중요해질 수 있습니다.
Hart Simha 2016 년

5
mydict.iteritems()대신에 사용한다면 아마도 같은 성능 일 것입니다. .items()다른 목록을 만듭니다.
Pat

64

다음은 Python 2.6의 예입니다.

>>> a = {1:1, 2:2, 3:3}
>>> dict((key,value) for key, value in a.iteritems() if key == 1)
{1: 1}

필터링 부분이 if문입니다.

이 방법은 매우 많은 키 중 몇 개만 선택하려는 경우 delnan의 답변보다 느립니다.


11
아마 if key in ('x','y','z')내가 사용하는 것을 제외하고는 추측합니다.
mpen

원하는 키를 이미 알고 있다면 delnan의 답변을 사용하십시오. if 문으로 각 키를 테스트해야하는 경우 ransford의 답변을 사용하십시오.
jnnnnn

1
이 솔루션에는 한 가지 장점이 더 있습니다. 값 비싼 함수 호출 (예 : a / old_dict는 함수 호출)에서 사전이 반환되면이 솔루션은 함수를 한 번만 호출합니다. 함수에 의해 반환 된 사전을 변수에 저장하는 명령형 환경에서 큰 문제는 아니지만 기능적 환경 (예 : 람다)에서는 이것이 중요한 관찰입니다.
gae123


20

코드 1 :

dict = { key: key * 10 for key in range(0, 100) }
d1 = {}
for key, value in dict.items():
    if key % 2 == 0:
        d1[key] = value

코드 2 :

dict = { key: key * 10 for key in range(0, 100) }
d2 = {key: value for key, value in dict.items() if key % 2 == 0}

코드 3 :

dict = { key: key * 10 for key in range(0, 100) }
d3 = { key: dict[key] for key in dict.keys() if key % 2 == 0}

모든 코드 조각 성능은 number = 1000을 사용하여 timeit로 측정되며 각 코드 조각마다 1000 번 수집됩니다.

여기에 이미지 설명을 입력하십시오

python 3.6의 경우 세 가지 방식의 필터 dict 키 성능이 거의 동일합니다. 파이썬 2.7 코드 3의 경우 약간 빠릅니다.


그냥 궁금해서 파이썬에서 그 음모를 꾸미셨습니까?
user5359531

1
ggplot2 in R- tidyverse의
keithpjolley 5

18

이 하나의 라이너 람다는 작동해야합니다.

dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])

예를 들면 다음과 같습니다.

my_dict = {"a":1,"b":2,"c":3,"d":4}
wanted_keys = ("c","d")

# run it
In [10]: dictfilt(my_dict, wanted_keys)
Out[10]: {'c': 3, 'd': 4}

그것은 dict 키 (i에서 x)를 반복하는 기본 목록 이해이며 키가 원하는 키 목록 (y)에 있으면 튜플 (키, 값) 쌍 목록을 출력합니다. dict ()는 전체를 감싸서 dict 객체로 출력합니다.


setfor를 사용해야 wanted_keys하지만 그렇지 않으면 좋아 보입니다.
mpen

원래 사전에 값 대신 목록이 포함되어 있으면 빈 사전이 나옵니다. 해결 방법이 있습니까?
FaCoffee

@Francesco, 예를 들어 주시겠습니까? 내가 실행하면 : 의도 한대로 dictfilt({'x':['wefwef',52],'y':['iuefiuef','efefij'],'z':['oiejf','iejf']}, ('x','z'))반환 {'x': ['wefwef', 52], 'z': ['oiejf', 'iejf']}됩니다.
Jim

나는 이것을 시도했다 : dict={'0':[1,3], '1':[0,2,4], '2':[1,4]}그리고 그 결과는 {}빈 dict 인 것으로 가정했다.
FaCoffee

"dict"는 예약어이므로 dict의 이름을 지정하는 데 사용해서는 안됩니다. 꺼내려고하는 열쇠는 무엇입니까? 내가 실행하면 foo = {'0':[1,3], '1':[0,2,4], '2':[1,4]}; dictfilt(foo,('0','2')), 나는 얻는다 : {'0': [1, 3], '2': [1, 4]}이것은 의도 된 결과이다
Jim

14

원래 사전 orig과 관심있는 항목 세트가 제공됩니다 keys.

filtered = dict(zip(keys, [orig[k] for k in keys]))

delnan의 답변만큼 좋지는 않지만 관심있는 모든 Python 버전에서 작동해야합니다. 그러나 keys원래 사전 에 존재 하는 각 요소에는 취약합니다 .


글쎄, 이것은 기본적으로 내 독해력 이해의 "튜플 생성기 버전"의 간절한 버전입니다. 2.4, 2005 년 봄에 제너레이터 표현식이 도입되었지만 실제로는 매우 호환 가능합니다.

1
동의하지 않습니다. 2.3 더 이상 존재하지 않아야합니다. 그러나 2.3 사용법에 대한 오래된 설문 조사 : moinmo.in/PollAboutRequiringPython24 짧은 버전 : RHEL4, SLES9, OS X 10.4와 함께 제공
Kai

7

delnan의 수락 된 답변을 바탕으로합니다.

원하는 키 중 하나가 old_dict에 없으면 어떻게합니까? delnan 솔루션은 포착 할 수있는 KeyError 예외를 발생시킵니다. 그것이 당신이 필요로하지 않는 경우 :

  1. old_dict와 want_keys 세트 모두에 존재하는 키만 포함하십시오.

    old_dict = {'name':"Foobar", 'baz':42}
    wanted_keys = ['name', 'age']
    new_dict = {k: old_dict[k] for k in set(wanted_keys) & set(old_dict.keys())}
    
    >>> new_dict
    {'name': 'Foobar'}
  2. old_dict에 설정되지 않은 키의 기본값이 있습니다.

    default = None
    new_dict = {k: old_dict[k] if k in old_dict else default for k in wanted_keys}
    
    >>> new_dict
    {'age': None, 'name': 'Foobar'}

당신은 또한 할 수 있습니다{k: old_dict.get(k, default) for k in ...}
Moberg

6

이 함수는 트릭을 수행합니다.

def include_keys(dictionary, keys):
    """Filters a dict by only including certain keys."""
    key_set = set(keys) & set(dictionary.keys())
    return {key: dictionary[key] for key in key_set}

delnan의 버전과 마찬가지로, 이것은 사전 이해력을 사용하며 큰 사전에 안정적인 성능을 제공합니다 (사전의 총 키 수가 아니라 허용하는 키 수에만 의존 함).

MyGGan의 버전과 마찬가지로이 키를 사용하면 키 목록에 사전에없는 키가 포함될 수 있습니다.

그리고 보너스로, 다음은 원본에서 특정 키를 제외하여 사전을 만들 수있는 역입니다.

def exclude_keys(dictionary, keys):
    """Filters a dict by excluding certain keys."""
    key_set = set(dictionary.keys()) - set(keys)
    return {key: dictionary[key] for key in key_set}

delnan의 버전과 달리 작업이 제대로 수행되지 않으므로 성능은 사전의 키 수와 관련이 있습니다. 그러나 이것의 장점은 함수가 제공된 사전을 수정하지 않는다는 것입니다.

편집 : dict에서 특정 키를 제외시키는 별도의 기능이 추가되었습니다.


집합이 받아들이는 keys것과 같은 모든 종류의 반복 가능한 것을 허용해야 합니다.
mpen

아, 잘 부탁드립니다. 지적 해 주셔서 감사합니다. 업데이트하겠습니다.
Ryan

두 가지 기능으로 더 나은지 궁금합니다. 만약 당신이 10 명에게 " 논쟁이 유지되거나 논쟁이 거부 되었다는 invert것을 암시 하는가?"라고 물었다면, 그들 중 몇 명은 동의 할 것입니까? keyskeys
skatenerd 2019

업데이트되었습니다. 당신이 무슨 생각을하는지 제게 알려주세요.
Ryan

입력 dict에 값 대신 목록이 있으면 작동하지 않는 것 같습니다. 이 경우 무효 한 dict을받습니다. 해결 방법이 있습니까?
FaCoffee

4

선택한 키를 제거한 상태로 새 사전을 만들려면 사전 이해
를 사용할 수 있습니다 . 예를 들면 다음과 같습니다.

d = {
'a' : 1,
'b' : 2,
'c' : 3
}
x = {key:d[key] for key in d.keys() - {'c', 'e'}} # Python 3
y = {key:d[key] for key in set(d.keys()) - {'c', 'e'}} # Python 2.*
# x is {'a': 1, 'b': 2}
# y is {'a': 1, 'b': 2}

산뜻한. Python 3에서만 작동합니다. Python 2는 "TypeError :-: '
list'and

파이썬 2에 대해 set (d.keys ())를 추가했습니다. 이것은 내가 실행할 때 작동합니다.
Srivastava

2

다른 옵션 :

content = dict(k1='foo', k2='nope', k3='bar')
selection = ['k1', 'k3']
filtered = filter(lambda i: i[0] in selection, content.items())

그러나 list() 가 아닌 (Python 2) 또는 iterator (Python 3)가 반환 filter()합니다 dict.


filtereddict당신은 사전을 다시 얻을!
CMCDragonkai

1

짧은 형식:

[s.pop(k) for k in list(s.keys()) if k not in keep]

간결성을 유지하기 위해 대부분의 답변에서 알 수 있듯이 a list또는로 복제 객체를 만들어야합니다 dict. 이것은 버림을 생성 list하지만 original의 키를 삭제합니다 dict.


0

del하나의 라이너에서 사용하는 또 다른 간단한 방법이 있습니다 .

for key in e_keys: del your_dict[key]

e_keys제외 할 키 목록입니다. 그것은 당신에게 새로운 것을주지 않고 당신의 받아쓰기를 업데이트 할 것입니다.

새로운 출력 dict을 원한다면 삭제하기 전에 dict의 사본을 만드십시오.

new_dict = your_dict.copy()           #Making copy of dict

for key in e_keys: del new_dict[key]

0

python-benedictdict 서브 클래스 인을 사용할 수 있습니다 .

설치: pip install python-benedict

from benedict import benedict

dict_you_want = benedict(your_dict).subset(keys=['firstname', 'lastname', 'email'])

GitHub의 오픈 소스입니다 : https://github.com/fabiocaccamo/python-benedict


면책 조항 : 나는이 도서관의 저자입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.