Estoy usando Python 2.7 con Windows 7.

Tengo un diccionario y me gustaría eliminar los valores que corresponden a pares (clave, valor) de otro diccionario.

Por ejemplo, tengo un diccionario t_dict. Me gustaría eliminar los pares correspondientes (clave, valor) que están en el diccionario values_to_remove para que termine con el diccionario final_dict

t_dict = {
    'a': ['zoo', 'foo', 'bar'],
    'c': ['zoo', 'foo', 'yum'],
    'b': ['tee', 'dol', 'bar']
}

values_to_remove = {
    'a': ['zoo'],
    'b': ['dol', 'bar']
}

# remove values here

print final_dict
{
    'a': ['foo', 'bar'],
    'c': ['zoo', 'foo', 'yum'],
    'b': ['tee']
}

He buscado páginas similares en SO y el documento de diccionarios de Python, pero no puedo encontrar nada para resolver este problema específico:

https://docs.python.org/2/library/stdtypes.html#dict

Cómo eliminar diccionarios con valores duplicados de un diccionario anidado

¿Cómo eliminar una clave de un diccionario de Python?

EDITAR

No puede haber valores duplicados en t_dict por clave. Por ejemplo, nunca habrá

t_dict['a'] = ['zoo','zoo','foo','bar']

1
BeeGee 11 may. 2016 a las 20:16

4 respuestas

La mejor respuesta

Como los duplicados no son posibles, podría tener sentido almacenar los valores como set, no como list. Si puede usar un set para t_dict, el proceso de eliminación es más rápido y sencillo de escribir (incluso más rápido si values_to_remove usa set o frozenset también) :

for k, toremove in values_to_remove.viewitems():
    t_dict.get(k, set()).difference_update(toremove)

Use lo anterior si values_to_remove se espera que sea pequeño, o si t_dict es más pequeño, puede cambiar a lo siguiente para evitar los set() s temporales (el tuple vacío es un singleton, por lo que no cuesta nada usarlo con dict.get):

for k, v in t_dict.viewitems():
    v.difference_update(values_to_remove.get(k, ()))

La opción final es el enfoque demasiado inteligente que elimina la necesidad de usar .get en absoluto al procesar solo las claves que aparecen en ambos dict s (usar -= requiere ambos dict s para use set para que los valores sean más cortos / rápidos, puede volver a difference_update si desea permitir valores que no sean set s para values_to_remove):

for k in (t_dict.viewkeys() & values_to_remove.viewkeys()):
    t_dict[k] -= values_to_remove[k]
3
ShadowRanger 11 may. 2016 a las 21:45

Cuando no desea tener los elementos duplicados en su dict, y el orden tampoco es tan importante, ¿por qué no utiliza set como valor de dic?

t_dict = {
    'a': set(['zoo', 'foo', 'bar']),
    'c': set(['zoo', 'foo', 'yum']),
    'b': set(['tee', 'dol', 'bar'])
}

values_to_remove = {
    'a': set(['zoo']),
    'b': set(['dol', 'bar'])
}

for k,v in values_to_remove.iteritems():
    t_dict[k] = t_dict[k]-v

print t_dict

>>>{'a': set(['foo', 'bar']), 'c': set(['foo', 'yum', 'zoo']), 'b': set(['tee'])}

Si el Pedido es importante para usted, también puede usar el OrderedSet como @sparkandshine en el comentario sugerido. http://orderedset.readthedocs.io/en/latest/

from ordered_set import OrderedSet
t_dict = {
    'a': OrderedSet(['zoo', 'foo', 'bar']),
    'c': OrderedSet(['zoo', 'foo', 'yum']),
    'b': OrderedSet(['tee', 'dol', 'bar'])
}

values_to_remove = {
    'a': OrderedSet(['zoo']),
    'b': OrderedSet(['dol', 'bar'])
}

for k,v in values_to_remove.iteritems():
    t_dict[k] = t_dict[k]-v

print t_dict

>>>{'a': OrderedSet(['foo', 'bar']), 'c': OrderedSet(['zoo', 'foo', 'yum']), 'b': OrderedSet(['tee'])}
1
xirururu 11 may. 2016 a las 18:28
for key,values in values_to_remove.items():
    for value in values:
        if key in t_dict and value in t_dict[key]:
            t_dict[key].pop(t_dict[key].index(value))
2
J.J 11 may. 2016 a las 17:28

Prueba esto,

for k, v in t_dict.items():
    for item in values_to_remove.get(k, ()):
        v.remove(item) 

# Output
{'a': ['foo', 'bar'], 'c': ['zoo', 'foo', 'yum'], 'b': ['tee']}
5
SparkAndShine 11 may. 2016 a las 17:34