Eliminar un elemento de un diccionario cuando se desconoce su clave


¿Cuál es la mejor manera de eliminar un elemento de un diccionario por valor, es decir, cuando la clave del elemento es desconocida? Aquí hay un enfoque simple:

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

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

Author: Jean-François Corbett, 2011-03-27

10 answers

Tenga en cuenta que actualmente está probando la identidad del objeto (is solo devuelve True si ambos operandos están representados por el mismo objeto en memoria; este no es siempre el caso con dos objetos que se comparan igual con ==). Si está haciendo esto a propósito, entonces 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 puede no hacer lo que quieres:

>>> 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 quieras != en lugar de is not.

 89
Author: Tim Pietzcker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-27 06:15:14
>>> dic = {'a':1, 'b':2}
>>> dic
{'a': 1, 'b': 2}
>>> dic.pop('c', 0)
0
>>> dic.pop('a', 0)
1
>>> dic
{'b': 2}
 116
Author: N 1.1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-27 05:55:31
a = {'name': 'your_name','class': 4}
if 'name' in a: del a['name']
 51
Author: Kracekumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-17 16:31:38

Una comparación simple 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

Entonces, deles más rápido que pop().

 40
Author: Luu Tuan Anh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-07 03:04:54

items() devuelve una lista, y es esa lista la que está iterando, por lo que mutar el dictado en el bucle no importa aquí. Si estuviera usando iteritems() en su lugar, mutar el dict en el bucle sería problemático, y lo mismo para viewitems() en Python 2.7.

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

 7
Author: mithrandi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-27 05:52:23

Construiría una lista de claves que necesitan ser eliminadas, luego las eliminaría. Es simple, eficiente y evita cualquier problema sobre iterar y mutar simultáneamente el dictado.

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]
 7
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-27 09:34:35

C es el nuevo diccionario, y a es su diccionario original, {'z','w'} son las teclas que desea eliminar de un

c = {key:a[key] for key in a.keys() - {'z', 'w'}}

Compruebe también: https://www.safaribooksonline.com/library/view/python-cookbook-3rd/9781449357337/ch01.html

 2
Author: priya khokher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-14 23:58:52

No hay nada malo en eliminar elementos del diccionario mientras se itera, como ha propuesto. Tenga cuidado con los subprocesos múltiples que utilizan el mismo diccionario al mismo tiempo, lo que puede resultar en un KeyError u otros problemas.

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

 0
Author: Thane Anthem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-27 05:55:24
y={'username':'admin','machine':['a','b','c']}
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]
 0
Author: user3559640,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-23 14:33:20

Así es como lo haría.

for key in some_dict.keys():
    if some_dict[key] == item_to_remove:
        some_dict.pop(key)
        break
 0
Author: Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-03 18:52:23