[python] 사전에서 요소 삭제

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

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



답변

del 요소를 제거합니다 :

del d[key]

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

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

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


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


답변

pop 사전을 변경합니다.

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

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


답변

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

>>> 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'}


답변

델 문은 당신이 찾고있는 것입니다. ‘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


답변

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

둘 다 사용할 수있는 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}


답변

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

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는 그 이유를 설명합니다. 그러나 이것은 공개 컬렉션 유형이 아닌 라이브러리의 숨겨진 구현 세부 사항입니다.


답변

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

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