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?


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

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.


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}

4
OP ditanya tentang kapan kunci tidak diketahui
— nmz787

52
a = {'name': 'your_name','class': 4}
if 'name' in a: del a['name']

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 () .


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.


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]

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')]

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


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.