사전에서 요소 삭제


1392

파이썬에서 사전에서 항목을 삭제하는 방법이 있습니까?

또한 사전에서 항목을 삭제하여 사본을 반환하려면 어떻게해야합니까 (예 : 원본을 수정하지 않음)?


13
사전을 직접 수정할 수 있는데 사전을 반환하는 함수가 필요한 이유는 무엇입니까?
amillerrhodes

5
사전 pop방법은 사전 변경 의 장소를 . 따라서 호출자에서 "도우미 함수"로 전달 된 사전에 대한 참조 를 변경합니다 . 따라서 "헬퍼 기능"은 호출자의 사전에 대한 원래 참조가 이미 변경되므로 아무것도 반환 할 필요가 없습니다. 필요하지 않은 경우 반품을 지정하지 마십시오 dict.pop(). 예 : do stuff with my_dict; my_dict.pop(my_key, None); do more stuff with my_dict # now doesn't have my_key. deepcopy(my_dict)필요한 경우 사용하십시오 .
Mark Mikofski

1
원래 제목은 세부 사항에 동의하지 않고 명백한 해결책을 구체적으로 배제했기 때문에 세부 d.pop()사항에 지정된 질문을하도록 제목을 수정했습니다.
smci

1
우리는 당신이 경우주의가 요구 추가해야 정말 이 작업을 수행 할 수는 E 요소를 사전에 N 번 할 경우 모두 깊은 사본 (/ 사용) O (N * E) 메모리 누수가 겠지만. 읽기 전용 (얕은 사본) 만 원한다면을 수행하십시오 d.pop(key). 그러나 얕은 사본을 수정하는 것이 있으면 앨리어싱에 잘 알려진 문제가 있습니다. 더 넓은 맥락을 알려 주면 도움이됩니다. (다른 어떤 것도 dict 값을 수정하고 있습니까? 목록을 파괴적으로 반복하려고합니까? 그렇지 않은 경우 어떻게해야합니까?)
smci

5
"사전을 직접 수정할 수 있는데 왜 사전을 반환하는 함수가 필요한가?" 아마도 매개 변수를 수정 하지 않는 순수한 함수를 작성하고 싶 습니까?
Gene Callahan

답변:


1726

del 요소를 제거합니다 :

del d[key]

그러나 이는 기존 사전을 변경하여 동일한 인스턴스에 대한 참조가있는 다른 사용자의 사전 내용을 변경합니다. 사전 을 반환하려면 사전을 복사하십시오.

def removekey(d, key):
    r = dict(d)
    del r[key]
    return r

dict()생성자는 만드는 얕은 사본을 . 딥 카피를 만들려면 copy모듈을 참조하십시오 .


모든 dict del/ assignment / etc에 대해 사본을 작성하십시오 . 일정 시간에서 선형 시간으로 이동하고 선형 공간을 사용한다는 의미입니다. 작은 받아쓰기의 경우 문제가되지 않습니다. 그러나 큰 dicts의 사본을 많이 만들 계획이라면 HAMT와 같은 다른 데이터 구조를 원할 것입니다 ( 이 답변에 설명되어 있음 ).


15
그것은 사전 +1의 변경 가능성에 대한 좋은 점입니다-사전의 사본을 원했던 시간을 생각할 수는 없지만 항상 '모두'사본에 의존했습니다. 좋은 지적입니다.
tMC

30
@tMC dict반복하면서 편집하면 오류가 발생합니다.RuntimeError: dictionary changed size during iteration
VertigoRay

15
무엇에 대한 pop사실 같은 작업을 수행하는 방법? 더 파이썬 적이 지 않습니까? (특별 예약어가 아닌 dict의 방법)?
서지

21
이 답변에는 약점이 있으며 오해의 소지가 있습니다. 독자들은 dict (d)가 'd'로 사본을 줄 수 있다고 오해 할 수 있습니다. 그러나 불완전한 사본입니다. Del 키 작업 만 수행해도 괜찮습니다. 그러나 중첩 된 dict에 다른 작업을 수행하려는 경우 해당 복사 방법을 사용하여 'r'을 수정하면 원래 'd'로 변경 될 수 있습니다. 정본을 얻으려면 먼저 'import copy'를 누른 다음 'r = copy.deepcopy (d)'가 필요합니다.
Zen

10
@ 젠 : 충분히, 나는 얕은 대 깊은 사본에 대한 메모를 추가했습니다.
Greg Hewgill

264

pop 사전을 변경합니다.

 >>> lol = {"hello": "gdbye"}
 >>> lol.pop("hello")
     'gdbye'
 >>> lol
     {}

원본을 보관하려면 복사 만하면됩니다.


29
"del"은 괜찮지 만 "pop"은 더 많은 "Pythonic"인 것 같습니다.
ivanleoncz

1
@ivanleoncz 왜?
kevr

3
pop'팝핑 된'값을 반환하므로 이후에이 값을 사용할 수 있습니다. 그것이 더 "Pythonic"이 아니라면, 나는 그것이 더 좋아 보인다고 말할 것입니다. 그것은 DICT 아니지만, 그것은 모두 같은 방식으로 작동합니다 : github.com/ivanlmj/python-prototypes/blob/master/3.4/...
ivanleoncz

2
@ivanleoncz 또한 한 가지 더 좋은 pop점이 있습니다. dict에서 키가 누락되면 반환되는 기본값을 제공 할 수 있습니다. 몇 개의 키를 제거해야 할 때 좋지만 일부 키가 누락되었을 수 있습니다. 그런 경우에 del던질 것 KeyError입니다.
itachi

80

귀하의 솔루션이 최선의 방법이라고 생각합니다. 그러나 다른 솔루션을 원하면 다음과 같이 지정된 키를 포함하지 않고 이전 사전의 키를 사용하여 새 사전을 만들 수 있습니다.

>>> a
{0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> {i:a[i] for i in a if i!=0}
{1: 'one', 2: 'two', 3: 'three'}

2
정말 멋진. 새로운 기능을 정의하지 않고 사전을 필터링하는 빠른 방법이 마음에 듭니다.
Joe J

6
이해력에 익숙하지 않은 사람들은 {i:a[i] for i in a if i not in [0, 1, 2]}여러 요소를 제거하려는 경우 다음과 같이 할 수도 있습니다 .
kmatheny

9
{k:v for k,v in a.items() if k != 0}내가 생각하는 것이 낫다 .
rlbond

1
키를 사용하여 항목을 제거하고 동일한 행에 새 dict의 결과를 반환하는 가장 좋은 솔루션입니다. 예를 들어, 당신은 같은 단일 항목없이 이미 구축 DICT를 사용해야 할 경우 **kwargs,some_function(**{k:v for k,v in some_dict.items() if k not 'some_key'})

최고의 솔루션입니다. 하나의 라이너와 원래 사전을 변경하지 않습니다.
Andrew Winterbotham

55

델 문은 당신이 찾고있는 것입니다. 'bar'라는 키가있는 foo라는 사전이있는 경우 다음과 같이 foo에서 'bar'를 삭제할 수 있습니다.

del foo['bar']

이렇게하면 조작중인 사전이 영구적으로 수정됩니다. 원래 사전을 유지하려면 사전에 사본을 작성해야합니다.

>>> foo = {'bar': 'baz'}
>>> fu = dict(foo)
>>> del foo['bar']
>>> print foo
{}
>>> print fu
{'bar': 'baz'}

dict호출은 얕은 복사본을 만듭니다. 깊은 사본을 원하면을 사용하십시오 copy.deepcopy.

편의를 위해 복사하여 붙여 넣을 수있는 방법은 다음과 같습니다.

def minus_key(key, dictionary):
    shallow_copy = dict(dictionary)
    del shallow_copy[key]
    return shallow_copy

1
@ pythonian29033 실제로는 no 입니다. 허용 된 답변은 예상대로 작동합니다. 하나의 키없이 dict를 반환합니다. 이 응답 변이 원래 딕셔너리에서 접근;)으로 significat의 차이가 있습니다
maxkoryukov가

1
@ arussell84, 왜 >>>파이썬 예제에서 자주 사용됩니까? 예, python-doc에는 많은 것들이 포함되어 있습니다. 그러나 이러한 코드는 copypaste에 편리하지 않습니다 . 혼란 스러워요
maxkoryukov

@maxkoryukov 응! 그러나 그 답변과 함수 안에있는 것을 제외하고는 그 함수 와이 답변은 정확히 같습니다. 그리고 당신은 파이썬으로 한동안 코딩하지 >>>
않았어야했는데

2
@ pythonian29033 님 >>>. 그렇습니다. REPL 스타일이지만 솔직하게 이야기합시다. 단 한 사람 만이이 샘플을 작성했으며 1000 명이 이것을 읽었습니다. 쉽게 복사하고 실행할 수있는 방식으로 예제를 작성하는 것이 좋습니다. 이 꺾쇠 괄호를 손으로 제거하고 싶지 않습니다. 또는 한 줄씩 복사하십시오. 그래서 이해가 안됩니다. 왜이 각도가 여전히 존재하는지)))) 뭔가를 모르고있을 수 있습니까?
maxkoryukov

3
편의를 위해 복사 / 붙여 넣기 기능을 추가했습니다.
arussell84

48

좋은 답변이 많이 있지만 한 가지만 강조하고 싶습니다.

둘 다 사용할 수있는 dict.pop()방법 및보다 일반적인 del문을 사전에서 항목을 제거 할 수 있습니다. 둘 다 원래 사전을 변경하므로 복사해야합니다 (아래 세부 사항 참조).

그리고 그들에게 KeyError제공하는 키가 사전에 없으면 두 가지 모두 a를 발생시킵니다.

key_to_remove = "c"
d = {"a": 1, "b": 2}
del d[key_to_remove]  # Raises `KeyError: 'c'`

key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove)  # Raises `KeyError: 'c'`

당신은 이것을 처리해야합니다 :

예외를 캡처하여 :

key_to_remove = "c"
d = {"a": 1, "b": 2}
try:
    del d[key_to_remove]
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

key_to_remove = "c"
d = {"a": 1, "b": 2}
try:
    d.pop(key_to_remove)
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

확인을 수행하여 :

key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
    del d[key_to_remove]

key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
    d.pop(key_to_remove)

그러나 pop()훨씬 더 간결한 방법이 있습니다-기본 반환 값을 제공하십시오.

key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove, None)  # No `KeyError` here

pop()키 값을 제거하기 위해 사용하지 않는 한 필요하지 않은 것을 제공 할 수 있습니다 None. 검사 del와 함께 사용 하면 오버 헤드를 일으키는 자체 합병증이있는 기능 으로 인해 약간 빠릅니다 . 일반적으로 그렇지 않으므로 기본값으로 충분합니다.inpop()pop()


주요 질문에 대해서는 사전 사전을 복사하여 원래 사전을 저장하고 키를 제거하지 않고 새 사전을 만들어야합니다.

여기에있는 다른 사람들은을 사용하여 전체 (깊은) 복사본을 만들 것을 제안 copy.deepcopy()합니다. 이는 과잉 copy.copy()이거나 "보통"(얕은) 복사본 이거나 또는를 사용하는 dict.copy()것으로 충분할 수 있습니다. 사전은 객체에 대한 참조를 키 값으로 유지합니다. 따라서 사전에서 키를 제거하면 참조되는 객체가 아니라이 참조가 제거됩니다. 메모리에 객체에 대한 다른 참조가 없으면 가비지 수집기에서 객체 자체를 나중에 자동으로 제거 할 수 있습니다. 딥 카피를 만들려면 얕은 카피에 비해 더 많은 계산이 필요하므로 카피를 만들고 메모리를 낭비하며 GC에 더 많은 작업을 제공하여 코드 성능이 떨어지며 때로는 카피가 충분합니다.

그러나 변경 가능한 객체를 사전 값으로 가지고 나중에 키없이 반환 된 사전에서 수정하려는 경우 딥 카피를 만들어야합니다.

얕은 사본으로 :

def get_dict_wo_key(dictionary, key):
    """Returns a **shallow** copy of the dictionary without a key."""
    _dict = dictionary.copy()
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3], "b": 2, "c": 3}
key_to_remove = "c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3], "b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3, 100], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3, 100], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2222}

깊은 사본으로 :

from copy import deepcopy


def get_dict_wo_key(dictionary, key):
    """Returns a **deep** copy of the dictionary without a key."""
    _dict = deepcopy(dictionary)
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3], "b": 2, "c": 3}
key_to_remove = "c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3], "b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2222}

20

… 사전에서 항목을 삭제하여 사본을 반환하려면 어떻게해야합니까 (예 : 원본을 수정하지 않음)?

A dict는 이것에 사용할 잘못된 데이터 구조입니다.

물론, dict을 복사하고 copy에서 튀어 나와서, 새로운 dict를 이해력으로 만드는 것도 마찬가지입니다. 그러나 모든 복사에는 시간이 걸립니다. 일정 시간 작업을 선형 시간 작업으로 대체했습니다. 그리고 한 번에 살아있는 모든 사본은 공간 당 공간, 즉 사본 당 선형 공간을 차지합니다.

같은 다른 데이터 구조는, 해시 배열이 시도를 매핑 , 사용 사례 정확히 이런 종류의 설계 : 추가하거나 요소를 반환에게 사본을 제거 대수 시간에, 원래와 스토리지의 대부분을 공유 . 1

물론 몇 가지 단점이 있습니다. 성능은 일정하지 않고 대수적입니다 (큰 기반 (일반적으로 32-128)이지만). 그리고 비 돌연변이 API를와 동일하게 만들 수 dict있지만 "돌연변이"API는 분명히 다릅니다. 그리고 무엇보다도 파이썬에는 HAMT 배터리가 포함되어 있지 않습니다. 2

pyrsistent라이브러리는 파이썬 HAMT 기반 DICT-교체 (및 기타 다양한 유형)의 꽤 튼튼하게 구현 한 것입니다. 또한 기존의 변경 코드를 영구 코드에 가능한 한 매끄럽게 이식 할 수 있는 멋진 진화 API 가 있습니다. 그러나 변경하지 않고 사본을 반환하는 것에 대해 명시 적으로 나타내려면 다음과 같이 사용하십시오.

>>> from pyrsistent import m
>>> d1 = m(a=1, b=2)
>>> d2 = d1.set('c', 3)
>>> d3 = d1.remove('a')
>>> d1
pmap({'a': 1, 'b': 2})
>>> d2
pmap({'c': 3, 'a': 1, 'b': 2})
>>> d3
pmap({'b': 2})

그것이 바로 d3 = d1.remove('a')질문이 요구하는 것입니다.

에 포함 dict되고에 list포함 된 가변 데이터 구조가있는 경우 pmap에도 앨리어싱 문제가 발생합니다. 불변으로 계속 진행하여 pmaps 및 pvectors를 포함 시켜서 만 수정할 수 있습니다 .


1. HAMT는 스칼라, 클로저, 하스켈과 같은 언어에서도 인기를 얻었습니다. 잠금이없는 프로그래밍 및 소프트웨어 트랜잭션 메모리와 매우 잘 작동하기 때문입니다.

2. 사실이 있다 의 구현에 사용되는 다음 stdlib에서 HAMT, contextvars. 이전에 철회 된 PEP는 그 이유를 설명합니다. 그러나 이것은 공개 컬렉션 유형이 아닌 라이브러리의 숨겨진 구현 세부 사항입니다.


19
d = {1: 2, '2': 3, 5: 7}
del d[5]
print 'd = ', d

결과: d = {1: 2, '2': 3}


14

del d [ 'key']에 전화하십시오.

그러나 프로덕션 환경에서는 항상 '키'가 있는지 확인하는 것이 좋습니다. d.

if 'key' in d:
    del d['key']

7
흠, 아니요, 프로덕션 환경에서는 EAFP 이념 을 따르는 것이 좋습니다 . try-except블록 에서 키를 제거하십시오 . 적어도 이것은 원자 작업이 될 것입니다;)
maxkoryukov

1
간결하고 싶을 때는 사용 d.pop('key', None)하십시오. 그러나 실제 질문은 사전을 수정하는 것이 아니라 하나의 키없이 사전을 얻는 것에 관한 것입니다. 그래서 이해 -여기에 좋은 선택입니다;)
maxkoryukov

7

아니요, 다른 방법은 없습니다

def dictMinus(dct, val):
   copy = dct.copy()
   del copy[val]
   return copy

그러나 종종 약간 변경된 사전의 사본을 작성하는 것은 비교적 큰 메모리 요구를 초래할 수 있으므로 좋은 생각이 아닙니다. 일반적으로 이전 사전을 기록하고 (필요한 경우) 수정하는 것이 좋습니다.


7
# mutate/remove with a default
ret_val = body.pop('key', 5)
# no mutation with a default
ret_val = body.get('key', 5)

5
>>> def delete_key(dict, key):
...     del dict[key]
...     return dict
... 
>>> test_dict = {'one': 1, 'two' : 2}
>>> print delete_key(test_dict, 'two')
{'one': 1}
>>>

이 오류 처리를하지 않습니다, 그것은 키가 DICT에 가정 먼저 있고 확인하시기 바랍니다 raise자사하지 않을 경우


10
방법과 다른 점은 del test_dict[key]무엇입니까?
Mad Physicist

5

여기에 최상위 디자인 접근법 :

def eraseElement(d,k):
    if isinstance(d, dict):
        if k in d:
            d.pop(k)
            print(d)
        else:
            print("Cannot find matching key")
    else:
        print("Not able to delete")


exp = {'A':34, 'B':55, 'C':87}
eraseElement(exp, 'C')

사전과 내가 원하는 키를 함수에 전달하고 사전인지 확인하고 키가 괜찮은지 확인하고 둘 다 존재하는 경우 사전에서 값을 제거하고 왼쪽을 인쇄합니다.

산출: {'B': 55, 'A': 34}

희망이 도움이됩니다!


3

아래 코드 스 니펫은 확실히 도움이 될 것입니다. 코드를 이해하는 데 도움이되는 각 줄에 주석을 추가했습니다.

def execute():
   dic = {'a':1,'b':2}
   dic2 = remove_key_from_dict(dic, 'b')  
   print(dict2)           # {'a': 1}
   print(dict)            # {'a':1,'b':2}

def remove_key_from_dict(dictionary_to_use, key_to_delete):
   copy_of_dict = dict(dictionary_to_use)     # creating clone/copy of the dictionary
   if key_to_delete in copy_of_dict :         # checking given key is present in the dictionary
       del copy_of_dict [key_to_delete]       # deleting the key from the dictionary 
   return copy_of_dict                        # returning the final dictionary

또는 dict.pop ()을 사용할 수도 있습니다

d = {"a": 1, "b": 2}

res = d.pop("c")  # No `KeyError` here
print (res)       # this line will not execute

또는 더 나은 접근법은

res = d.pop("c", "key not found")
print (res)   # key not found
print (d)     # {"a": 1, "b": 2}

res = d.pop("b", "key not found")
print (res)   # 2
print (d)     # {"a": 1}

2

다음은 목록 이해를 사용하는 또 다른 변형입니다.

original_d = {'a': None, 'b': 'Some'}
d = dict((k,v) for k, v in original_d.iteritems() if v)
# result should be {'b': 'Some'}

이 방법은이 게시물의 답변을 기반으로합니다. 공백에서 빈 문자열이있는 키를 제거하는 효율적인 방법


1
이미 간단하고 적절하고 수용 가능한 답변이있는 오래된 질문에 대답하려면 최소한 답변이 올바른지 확인하십시오. 이것은 OP가 요청한 것을 수행하지 않습니다.
user2357112는

나는 일반적으로 중요한 정보를 추가 할 수 있다고 생각되는 질문에 대해서는 날짜를 확인하지 않습니다. 또한, 내가 링크 된 질문에 댓글 하나 당 : "일반적으로이 사람이 원하는 정확히 무엇이며, 아마도 어떤 OP 요구이지만, 영업 이익은 요청 것이 아니다" stackoverflow.com/questions/12118695/...의 I 그것이 질문에 대한 직접적인 대답이 아니라는 것을 알고 있었다. 오히려 옵션의 확장.
BigBlueHat

3
이 답변은 완전하지는 않지만 if 조건을 사용하여 항목을 제거 할 수 있음을 알 수 있습니다. op if vif k is not 'a'응답하도록 변경 했습니다 . 그러나 그것이 효율적인 방법이라고 생각하지 않습니다. 이것은 pop 또는 del처럼 O (log n) 대신 O (n)의 요소를 제거합니다.
holgac

0
    species = {'HI': {'1': (1215.671, 0.41600000000000004),
  '10': (919.351, 0.0012),
  '1025': (1025.722, 0.0791),
  '11': (918.129, 0.0009199999999999999),
  '12': (917.181, 0.000723),
  '1215': (1215.671, 0.41600000000000004),
  '13': (916.429, 0.0005769999999999999),
  '14': (915.824, 0.000468),
  '15': (915.329, 0.00038500000000000003),
 'CII': {'1036': (1036.3367, 0.11900000000000001), '1334': (1334.532, 0.129)}}

다음 코드는 dict의 사본을 만들고 species항목이 아닌 항목을 삭제합니다.trans_HI

trans_HI=['1025','1215']
for transition in species['HI'].copy().keys():
    if transition not in trans_HI:
        species['HI'].pop(transition)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.