2011-03-27 18 views
96

¿Cuál es la mejor manera de eliminar un elemento de un diccionario cuando se desconoce la clave del elemento? Aquí hay un enfoque simple:¿La mejor manera de eliminar un elemento de un diccionario de Python?

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

¿Hay formas mejores? ¿Hay algo de malo en mutar (eliminar elementos) del diccionario mientras se lo itera?

+1

La razón para prohibir subrayado mutando dict al iterar es porque internamente hay una orden para la iteración, si mutar las teclas, el orden sería socavada, lo que da como resultado un comportamiento desconocido. – 8090PZ

+0

Posible duplicado de [¿Cómo eliminar una clave de un diccionario de Python?] (Http://stackoverflow.com/questions/11277432/how-to-remove-a-key-from-a-python-dictionary) – tripleee

Respuesta

83

Tenga en cuenta que actualmente está realizando una prueba de la identidad del objeto (is sólo se devuelve True si ambos operandos son representados por el mismo objeto en la memoria - esto no es siempre el caso con dos objetos que se compara con igual ==). Si usted está haciendo esto a propósito, entonces se podría reescribir su código como

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

pero esto no puede hacer lo que quiera:

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

Así que probablemente quieren != en lugar de is not.

+2

Es eso una compresión de diccionario? ¿Cuándo fueron agregados? – Buttons840

+3

puede usar 'some_dict.iteritems() 'aquí y poner declaraciones' for' y 'if' en líneas separadas para la legibilidad – jfs

+3

Creo que se agregaron las comprensiones del diccionario en Python 2.7. – mithrandi

7

items() devuelve una lista, y es esa lista la que estás iterando, por lo que mutar el dict en el bucle no importa aquí. Si estaba usando iteritems() en su lugar, mutando el dict en el bucle would be problematic, y lo mismo para viewitems() en Python 2.7.

No puedo pensar en una mejor manera de eliminar elementos de un dict por valor.

0

No hay nada de malo en borrar elementos del diccionario durante la iteración, como ha propuesto. Tenga cuidado con varios subprocesos usando el mismo diccionario al mismo tiempo, lo que puede ocasionar un error clave u otros problemas.

Por supuesto, ver los documentos en http://docs.python.org/library/stdtypes.html#typesmapping

+0

'para k, v en d.iteritems(): del d [k]' daría 'RuntimeError: tamaño del diccionario cambiado durante la iteración'. Vea la explicación de mithrandi. – Buttons840

+1

Por supuesto, d.iteritems() no es como se repite el cartel original, y no a lo que me refería en mi respuesta. –

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 preguntado con respecto a cuándo se desconoce la clave – nmz787

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

construiría una lista de claves que necesitan la eliminación, luego eliminarlos. Es simple, eficiente y evita cualquier problema sobre la iteración simultánea y la mutación del dict.

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

Una simple comparación entre del y 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) 

resultado:

0.0329667857143 
0.0451040902256 

Así, del es más rápido que pop() .

+6

Sin embargo, la diferencia de rendimiento no es buena, y si no desea generar una excepción, puede proporcionar un segundo argumento para '' pop() '' (como @ n-1-1 hace arriba) - que no es una opción para el operador '' del''. –

+1

Auxiliar a la pregunta, pero también he estado luchando por entender 'timeit'. Gracias por este claro ejemplo. –

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