2011-03-27 4 views
96

Quelle est la meilleure façon de supprimer un élément d'un dictionnaire lorsque la clé de l'élément est inconnue? Voici une approche simple:La meilleure façon de supprimer un élément d'un dictionnaire Python?

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

Y a-t-il de meilleurs moyens? Y at-il un problème avec la mutation (suppression d'éléments) du dictionnaire lors de son itération?

+1

La raison underline pour interdire dict muter en est parce itération interne il y a un ordre pour l'itération, si vous muter les clés, l'ordre serait compromis, ce qui entraîne un comportement inconnu. – 8090PZ

+0

Copie possible de [Comment supprimer une clé d'un dictionnaire python?] (Http://stackoverflow.com/questions/11277432/how-to-remove-a-key-from-a-python-dictionary) – tripleee

Répondre

83

Soyez conscient que vous êtes en train de tester l'identité d'objet (is renvoie uniquement True si les deux opérandes sont représentés par le même objet en mémoire - ce n'est pas toujours le cas avec deux objets qui permettent de comparer l'égalité avec ==). Si vous faites exprès, vous pouvez réécrire votre code comme

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

Mais cela peut ne pas faire ce que vous voulez:

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

Donc, vous voulez probablement != au lieu de is not.

+2

une compression de dictionnaire? Quand ont-ils été ajoutés? – Buttons840

+3

vous pourriez utiliser 'some_dict.iteritems() 'ici et place les instructions' for' et 'if' sur des lignes séparées pour la lisibilité – jfs

+3

Je crois que les compréhensions de dictionnaire ont été ajoutées dans Python 2.7. – mithrandi

7

items() renvoie une liste, et c'est cette liste que vous itérez, donc la modification de la dict dans la boucle n'a pas d'importance ici. Si vous utilisiez iteritems() à la place, en modifiant la dict dans la boucle would be problematic, et de même pour viewitems() dans Python 2.7.

Je ne trouve pas de meilleur moyen de supprimer des éléments d'une dict par valeur.

0

Il n'y a rien de mal à supprimer des éléments du dictionnaire pendant l'itération, comme vous l'avez proposé. Faites attention à plusieurs threads utilisant le même dictionnaire en même temps, ce qui peut entraîner une erreur KeyError ou d'autres problèmes.

Bien sûr, voir les docs à http://docs.python.org/library/stdtypes.html#typesmapping

+0

'pour k, v dans d.iteritems(): del d [k]' donnerait 'RuntimeError: le dictionnaire a changé de taille pendant l'itération'. Voir l'explication de mithrandi. – Buttons840

+1

Bien sûr, d.iteritems() n'est pas la façon dont l'affiche originale est itérative, et pas ce dont je parlais dans ma réponse. –

106
>>> dic = {'a':1, 'b':2} 
>>> dic 
{'a': 1, 'b': 2} 
>>> dic.pop('c', 0) 
0 
>>> dic.pop('a', 0) 
1 
>>> dic 
{'b': 2} 
+1

OP a demandé quand la clé est inconnue – nmz787

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

Je construis une liste de clés qui ont besoin d'enlever, puis les retirer. C'est simple, efficace et évite tout problème d'itération simultanée et de mutation de la dictée.

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] 
35

Une simple comparaison entre del et 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) 

Résultat:

0.0329667857143 
0.0451040902256 

Ainsi, del est plus rapide que pop() .

+6

Cependant, la différence de performance n'est pas grande, et si vous voulez éviter de lever une exception, vous pouvez fournir un second argument à '' pop() '' (comme @ n-1-1 fait ci-dessus) - ce qui n'est pas une option pour l'opérateur '' del''. –

+1

Ancillaire à la question, mais j'avais aussi du mal à comprendre «timeit». Merci pour cet exemple clair. –

1
y={'username':'admin','machine':['a','b','c']} 
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')] 
Questions connexes