BeeGee
BeeGee

Reputation: 875

Remove values from lists of values in a dictionary

I am using Python 2.7 with Windows 7.

I have a dictionary and would like to remove values that correspond to (key, value) pairs from another dictionary.

For example, I have a dictionary t_dict. I would like to remove corresponding (key,value) pairs that are in the dictionary values_to_remove so that I end up with dictionary 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']
}

I have looked at similar pages on SO and the python dictionaries doc but cannot find anything to solve this specific problem:

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

How to remove dictionaries with duplicate values from a nested dictionary

How to remove a key from a python dictionary?

EDIT

There cannot be duplicate values in t_dict per key. For example there will never be

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

Upvotes: 1

Views: 182

Answers (4)

ShadowRanger
ShadowRanger

Reputation: 155323

Since duplicates aren't possible, it might make sense to store the values as a set, not a list. If you can use a set for t_dict, the removal process is both faster and simpler to write (even faster if values_to_remove uses set or frozenset too):

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

Use the above if values_to_remove expected to be small, or if t_dict is smaller, you could switch to the following to avoid the temporary set()s (the empty tuple is a singleton, so it costs nothing to use it with dict.get):

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

Final option is the overly clever approach that removes the need for using .get at all by only processing keys that appear in both dicts (using -= requires both dicts to use set for values to be shorter/faster, you could go back to difference_update if you want to allow non-sets for values_to_remove's values):

for k in (t_dict.viewkeys() & values_to_remove.viewkeys()):
    t_dict[k] -= values_to_remove[k]

Upvotes: 3

xirururu
xirururu

Reputation: 5508

When you don't want to have the duplicated elements in your dict, and the order also not so important, why don't use set as you dic value?

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

If the Order important for you, you can also use the OrderedSet like @sparkandshine in comment suggested. 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'])}

Upvotes: 1

SparkAndShine
SparkAndShine

Reputation: 17997

Try this,

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

Upvotes: 5

J.J
J.J

Reputation: 3607

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))

Upvotes: 2

Related Questions