Hapus item dari kamus ketika kuncinya tidak diketahui

112

Apa cara terbaik untuk menghapus item dari kamus berdasarkan nilai, yaitu ketika kunci item tidak diketahui? Inilah pendekatan sederhana:

for key, item in some_dict.items():
    if item is item_to_remove:
        del some_dict[key]

Apakah ada cara yang lebih baik? Apakah ada yang salah dengan mutasi (menghapus item) dari kamus saat mengulanginya?

Kancing 840
sumber
1
Alasan yang digarisbawahi untuk melarang mutasi dict saat mengulanginya adalah karena secara internal ada perintah untuk iterasi, jika Anda mematikan kunci, urutannya akan rusak, yang menghasilkan perilaku yang tidak diketahui.
Spectral
Kemungkinan duplikat dari Bagaimana cara menghapus kunci dari kamus python?
tripleee

Jawaban:

92

Ketahuilah bahwa Anda saat ini menguji identitas objek ( ishanya mengembalikan Truejika kedua operan diwakili oleh objek yang sama di memori - tidak selalu demikian dengan dua objek yang dibandingkan sama ==). Jika Anda melakukan ini dengan sengaja, maka Anda dapat menulis ulang kode Anda sebagai

some_dict = {key: value for key, value in some_dict.items() 
             if value is not value_to_remove}

Tetapi ini mungkin tidak melakukan apa yang Anda inginkan:

>>> some_dict = {1: "Hello", 2: "Goodbye", 3: "You say yes", 4: "I say no"}
>>> value_to_remove = "You say yes"
>>> some_dict = {key: value for key, value in some_dict.items() if value is not value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 3: 'You say yes', 4: 'I say no'}
>>> some_dict = {key: value for key, value in some_dict.items() if value != value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 4: 'I say no'}

Jadi, Anda mungkin menginginkannya, !=bukan is not.

Tim Pietzcker
sumber
2
Apakah itu kompresi kamus? Kapan mereka ditambahkan?
Buttons840
4
Anda dapat menggunakan di some_dict.iteritems()sini dan meletakkan fordan ifpernyataan pada baris terpisah agar mudah dibaca
jfs
3
Saya percaya pemahaman kamus ditambahkan dengan Python 2.7.
mithrandi
2
@ JF Sebastian: Saya menggunakan Python 3, dan iteritemssekarang items. Di Python 2.7, iteritems()memang lebih baik.
Tim Pietzcker
1
@ Buttons840 mereka disebut pemahaman dict di PEP 274 atau tampilan kamus . seperti yang dikatakan PEP bahwa mereka ditambahkan di 2.7 sebagai prestasi 3.x backport. sebagai alternatif Anda dapat memberi makan dict()dengan ekspresi generator yang sesuai, yaitu 2.4. meta: dapat menelusuri peps di sini untuk mencari tahu.
n611x007
120

The dict.pop(key[, default])Metode memungkinkan Anda untuk menghapus item ketika Anda tahu kuncinya. Ia mengembalikan nilai pada kunci jika menghapus item, jika tidak ia mengembalikan apa yang diteruskan sebagai default. Lihat dokumennya . '

Contoh:

>>> dic = {'a':1, 'b':2}
>>> dic
{'a': 1, 'b': 2}
>>> dic.pop('c', 0)
0
>>> dic.pop('a', 0)
1
>>> dic
{'b': 2}
N 1.1
sumber
4
OP ditanya tentang kapan kunci tidak diketahui
nmz787
52
a = {'name': 'your_name','class': 4}
if 'name' in a: del a['name']
Kracekumar
sumber
OP ditanya tentang kapan kunci tidak diketahui. Jawaban ini mengasumsikan bahwa kuncinya sudah diketahui.
Jean-François Corbett
42

Perbandingan sederhana antara del dan pop () :

import timeit
code = """
results = {'A': 1, 'B': 2, 'C': 3}
del results['A']
del results['B']
"""
print timeit.timeit(code, number=100000)
code = """
results = {'A': 1, 'B': 2, 'C': 3}
results.pop('A')
results.pop('B')
"""
print timeit.timeit(code, number=100000)

hasil:

0.0329667857143
0.0451040902256

Jadi, del lebih cepat dari pop () .

Luu Tuan Anh
sumber
6
Namun, perbedaan performanya tidak besar, dan jika Anda ingin menghindari munculnya pengecualian, Anda dapat memberikan argumen kedua ke pop()(seperti yang dilakukan @ n-1-1 di atas) - yang bukan merupakan opsi untuk deloperator.
Alex Dupuy
1
Selain pertanyaan itu, saya juga telah berjuang untuk memahami timeit. Terima kasih atas contoh yang jelas ini.
Adam_G
OP ditanya tentang kapan kunci tidak diketahui. Jawaban ini mengasumsikan bahwa kuncinya sudah diketahui.
Jean-François Corbett
7

items()mengembalikan daftar, dan itu adalah daftar yang Anda iterasi, jadi mutasi dict di loop tidak masalah di sini. Jika Anda menggunakan iteritems()sebagai gantinya, mutasi dict dalam loop akan menjadi masalah , dan juga untuk viewitems()Python 2.7.

Saya tidak bisa memikirkan cara yang lebih baik untuk menghapus item dari dict by value.

mithrandi.dll
sumber
7

Saya akan membuat daftar kunci yang perlu dihapus, lalu menghapusnya. Sederhana, efisien, dan menghindari masalah tentang pengulangan dan mutasi perintah secara bersamaan.

keys_to_remove = [key for key, value in some_dict.iteritems()
                  if value == value_to_remove]
for key in keys_to_remove:
    del some_dict[key]

sumber
OP ditanya tentang kapan kunci tidak diketahui. Jawaban ini mengasumsikan bahwa kuncinya sudah diketahui.
Jean-François Corbett
1
y={'username':'admin','machine':['a','b','c']}
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]
pengguna3559640
sumber
0

Tidak ada yang salah dengan menghapus item dari kamus saat mengulang, seperti yang Anda usulkan. Berhati-hatilah dengan beberapa utas yang menggunakan kamus yang sama pada saat yang sama, yang dapat mengakibatkan KeyError atau masalah lainnya.

Tentu saja, lihat dokumen di http://docs.python.org/library/stdtypes.html#typesmapping

Lagu Kebangsaan
sumber
for k,v in d.iteritems(): del d[k]akan memberi RuntimeError: dictionary changed size during iteration. Simak penjelasan mithrandi.
Buttons840
1
Tentu saja, d.iteritems () bukanlah cara pengulangan poster asli, dan bukan yang saya maksud dalam jawaban saya.
Thane Anthem
0

Beginilah cara saya melakukannya.

for key in some_dict.keys():
    if some_dict[key] == item_to_remove:
        some_dict.pop(key)
        break
Nathan
sumber