Bir öğeyi, anahtarı bilinmediğinde sözlükten kaldırın


112

Bir öğeyi sözlükten değere göre kaldırmanın en iyi yolu nedir, yani öğenin anahtarı bilinmediğinde? İşte basit bir yaklaşım:

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

Daha iyi yollar var mı? Sözlüğü yinelerken sözlükten değiştirmenin (öğeleri silmenin) yanlış bir yanı var mı?


1
Değişen dikteyi yinelerken yasaklamanın altı çizili nedeni, dahili olarak yineleme için bir emir olması, anahtarları değiştirirseniz, sıranın zayıflayacağı ve bunun da bilinmeyen davranışla sonuçlanacağıdır.
Spectral

Yanıtlar:


92

Şu anda nesne kimliğini test ettiğinizi unutmayın ( isyalnızca Trueher iki işlenen bellekte aynı nesne tarafından temsil ediliyorsa geri döner - bu, birbirine eşit olan iki nesne için her zaman geçerli değildir ==). Bunu bilerek yapıyorsanız, kodunuzu şu şekilde yeniden yazabilirsiniz:

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

Ancak bu, istediğinizi yapmayabilir:

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

Yani muhtemelen !=yerine istiyorsun is not.


2
Bu bir sözlük sıkıştırması mı? Ne zaman eklendi?
Buttons840

4
some_dict.iteritems()burada kullanabilir forve ififadeleri okunabilirlik için ayrı satırlara koyabilirsiniz
jfs

3
Python 2.7'de sözlük anlamalarının eklendiğine inanıyorum.
mithrandi

2
@JF Sebastian: Python 3'teyim ve iteritemsşimdi items. Python 2.7'de iteritems()gerçekten daha iyi.
Tim Pietzcker

1
@ Buttons840 bunlara PEP 274 veya sözlük ekranlarında dikte anlamaları denir . PEP'in dediği gibi, bunlar 2.7'ye arkaplanlı 3.x özellikleri olarak eklendi . alternatif dict()olarak 2.4 olan uygun bir jeneratör ifadesi ile besleyebilirsiniz . meta: bir şeyler bulmak için buradaki pepslere göz atabilir .
n611x007

120

dict.pop(key[, default])Yöntem anahtarı biliyorum zaman öğeleri kaldırmak için izin verir. Öğeyi kaldırırsa anahtardaki değeri döndürür, aksi takdirde iletileni döndürür default. Dokümanlara bakın .

Misal:

>>> 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, anahtarın ne zaman bilinmediğiyle ilgili sordu
nmz787

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

OP, anahtarın ne zaman bilinmediğiyle ilgili sordu. Bu cevap, anahtarın bilindiğini varsayar.
Jean-François Corbett

42

Del ve pop () arasında basit bir karşılaştırma :

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)

sonuç:

0.0329667857143
0.0451040902256

Yani del , pop () ' dan daha hızlıdır .


6
Bununla birlikte, performans farkı çok büyük değildir ve bir istisna oluşturmaktan kaçınmak istiyorsanız, ikinci bir argüman sunabilirsiniz pop()(@ n-1-1'in yukarıda yaptığı gibi) - bu deloperatör için bir seçenek değildir .
Alex Dupuy

1
Soruya yardımcı ama ben de anlamakta zorlanıyordum timeit. Bu açık örnek için teşekkür ederim.
Adam_G

OP, anahtarın ne zaman bilinmediğiyle ilgili sordu. Bu cevap, anahtarın bilindiğini varsayar.
Jean-François Corbett

7

items()bir liste döndürür ve yinelediğiniz listedir, bu nedenle döngüdeki dikteyi değiştirmenin burada bir önemi yoktur. iteritems()Bunun yerine kullanıyorsanız , döngüdeki dikteyi değiştirmek sorunlu olabilir ve aynı şekilde viewitems()Python 2.7 için de geçerlidir.

Öğeleri bir dikteden değere göre çıkarmanın daha iyi bir yolunu düşünemiyorum.


7

Kaldırılması gereken anahtarların bir listesini oluşturup sonra kaldırırdım. Basit, etkilidir ve dikteyi aynı anda yinelemek ve değiştirmekle ilgili herhangi bir sorunu ortadan kaldırır.

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, anahtarın ne zaman bilinmediğiyle ilgili sordu. Bu cevap, anahtarın bilindiğini varsayar.
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

Önerdiğiniz gibi, yineleme yaparken sözlükten öğe silmede yanlış bir şey yoktur. Aynı sözlüğü aynı anda kullanan birden fazla iş parçacığı konusunda dikkatli olun, bu bir KeyError hatası veya başka sorunlara neden olabilir.

Elbette http://docs.python.org/library/stdtypes.html#typesmapping adresindeki belgelere bakın.


for k,v in d.iteritems(): del d[k]verecekti RuntimeError: dictionary changed size during iteration. Mitrandi'nin açıklamasına bakın.
Buttons840

1
Tabii ki, d.iteritems () orijinal posterin nasıl yinelendiği ve cevabımda bahsettiğim şey değil.
Thane Marşı

0

Ben böyle yapardım.

for key in some_dict.keys():
    if some_dict[key] == item_to_remove:
        some_dict.pop(key)
        break
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.