113
votes

What is the best way to remove an item from a dictionary by value, i.e. when the item's key is unknown? Here's a simple approach:

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

Are there better ways? Is there anything wrong with mutating (deleting items) from the dictionary while iterating it?

10
The underline reason for prohibiting mutating dict while iterating it is because internally there is an order for iteration, if you mutate the keys, the order would be undermined, which results unknown behavior. - Spectral

10 Answers

92
votes

Be aware that you're currently testing for object identity (is only returns True if both operands are represented by the same object in memory - this is not always the case with two object that compare equal with ==). If you are doing this on purpose, then you could rewrite your code as

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

But this may not do what you want:

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

So you probably want != instead of is not.

119
votes

The dict.pop(key[, default]) method allows you to remove items when you know the key. It returns the value at the key if it removes the item otherwise it returns what is passed as default. See the docs.'

Example:

>>> dic = {'a':1, 'b':2}
>>> dic
{'a': 1, 'b': 2}
>>> dic.pop('c', 0)
0
>>> dic.pop('a', 0)
1
>>> dic
{'b': 2}
52
votes
a = {'name': 'your_name','class': 4}
if 'name' in a: del a['name']
42
votes

A simple comparison between del and 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)

result:

0.0329667857143
0.0451040902256

So, del is faster than pop().

8
votes

I'd build a list of keys that need removing, then remove them. It's simple, efficient and avoids any problem about simultaneously iterating over and mutating the 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]
7
votes

items() returns a list, and it is that list you are iterating, so mutating the dict in the loop doesn't matter here. If you were using iteritems() instead, mutating the dict in the loop would be problematic, and likewise for viewitems() in Python 2.7.

I can't think of a better way to remove items from a dict by value.

2
votes

c is the new dictionary, and a is your original dictionary, {'z','w'} are the keys you want to remove from a

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

Also check: https://www.safaribooksonline.com/library/view/python-cookbook-3rd/9781449357337/ch01.html

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

There is nothing wrong with deleting items from the dictionary while iterating, as you've proposed. Be careful about multiple threads using the same dictionary at the same time, which may result in a KeyError or other problems.

Of course, see the docs at http://docs.python.org/library/stdtypes.html#typesmapping

0
votes

This is how I would do it.

for key in some_dict.keys():
    if some_dict[key] == item_to_remove:
        some_dict.pop(key)
        break