[python] 사전을 반복하면서 사전에서 항목을 삭제하는 방법은 무엇입니까?

반복하면서 파이썬의 사전에서 항목을 삭제하는 것이 합법적입니까?

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

for k, v in mydict.iteritems():
   if k == val:
     del mydict[k]

아이디어는 반복되는 사전의 하위 세트 인 새 사전을 작성하는 대신 사전에서 특정 조건을 충족하지 않는 요소를 제거하는 것입니다.

이것이 좋은 해결책입니까? 더 우아하고 효율적인 방법이 있습니까?



답변

편집하다:

이 답변은 Python3에서는 작동하지 않으며을 제공합니다 RuntimeError.

RuntimeError : 반복하는 동안 사전 크기가 변경되었습니다.

mydict.keys()목록이 아닌 반복자를 반환 하기 때문에 발생 합니다. 의견에서 지적했듯이 간단히 mydict.keys()목록으로 변환 하면 list(mydict.keys())작동합니다.


콘솔의 간단한 테스트는 사전을 반복하는 동안 사전을 수정할 수 없음을 보여줍니다.

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k, v in mydict.iteritems():
...    if k == 'two':
...        del mydict[k]
...
------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

delnan의 답변에서 언급했듯이 항목을 삭제하면 반복자가 다음 항목으로 이동하려고 할 때 문제가 발생합니다. 대신, keys()메소드를 사용하여 키 목록을 가져 와서 작업하십시오.

>>> for k in mydict.keys():
...    if k == 'two':
...        del mydict[k]
...
>>> mydict
{'four': 4, 'three': 3, 'one': 1}

items 값을 기준으로 삭제 해야하는 경우 items()대신 메소드를 사용하십시오 .

>>> for k, v in mydict.items():
...     if v == 3:
...         del mydict[k]
...
>>> mydict
{'four': 4, 'one': 1}


답변

두 단계로 수행 할 수도 있습니다.

remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]

내가 가장 좋아하는 접근법은 일반적으로 새로운 전략을 만드는 것입니다.

# Python 2.7 and 3.x
mydict = { k:v for k,v in mydict.items() if k!=val }
# before Python 2.7
mydict = dict((k,v) for k,v in mydict.iteritems() if k!=val)


답변

반복하는 동안 컬렉션을 수정할 수 없습니다. 그 방법은 광기입니다-가장 눈에 띄게, 현재 항목을 삭제하고 삭제하도록 허용 된 경우 반복자가 (+1) 이동해야하고 다음 호출 next은 그 이상으로 넘어갈 것입니다 (+2). 한 요소 (삭제 한 요소 바로 뒤에있는 요소)를 건너 뜁니다. 두 가지 옵션이 있습니다.

  • 모든 키 (또는 필요한 것에 따라 값 또는 둘 다)를 복사 한 다음 반복하십시오. .keys()이것을 위해 et al을 사용할 수 있습니다 (Python 3에서는 결과 반복자를에 전달하십시오 list). 공간적으로 많은 낭비가 될 수 있습니다.
  • mydict평소와 같이 반복 하여 별도의 컬렉션에서 삭제할 키를 저장합니다 to_delete. 당신이 반복하는 일을 할 때 mydict, 모든 항목을 삭제 to_delete에서 mydict. 첫 번째 접근 방식에서 일부 (삭제 된 키 수 및 유지 수에 따라) 공간을 절약 할 수 있지만 몇 줄이 더 필요합니다.

답변

대신에 반환 된 것과 같은 사본을 반복하십시오 items().

for k, v in list(mydict.items()):


답변

사용하는 것이 가장 깨끗합니다 list(mydict).

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k in list(mydict):
...     if k == 'three':
...         del mydict[k]
...
>>> mydict
{'four': 4, 'two': 2, 'one': 1}

이것은 목록의 병렬 구조에 해당합니다.

>>> mylist = ['one', 'two', 'three', 'four']
>>> for k in list(mylist):                            # or mylist[:]
...     if k == 'three':
...         mylist.remove(k)
...
>>> mylist
['one', 'two', 'four']

둘 다 python2와 python3에서 작동합니다.


답변

사전 이해력을 사용할 수 있습니다.

d = {k:d[k] for k in d if d[k] != val}


답변

python3을 사용하면 dic.keys ()를 반복하면 사전 크기 오류가 발생합니다. 이 대체 방법을 사용할 수 있습니다.

python3으로 테스트 한 결과 제대로 작동하고 ” 반복 중 크기가 변경된 사전 “오류 가 발생하지 않습니다.

my_dic = { 1:10, 2:20, 3:30 }
# Is important here to cast because ".keys()" method returns a dict_keys object.
key_list = list( my_dic.keys() )

# Iterate on the list:
for k in key_list:
    print(key_list)
    print(my_dic)
    del( my_dic[k] )


print( my_dic )
# {}