116

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?

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
Buttons840
  • 9,239
  • 15
  • 58
  • 85
  • 2
    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. –  Jul 26 '15 at 19:21
  • Possible duplicate of [How to remove a key from a python dictionary?](http://stackoverflow.com/questions/11277432/how-to-remove-a-key-from-a-python-dictionary) – tripleee Mar 24 '17 at 09:01

10 Answers10

118

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}
FelisPhasma
  • 332
  • 5
  • 13
N 1.1
  • 12,418
  • 6
  • 43
  • 61
93

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.

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • 2
    Is that a dictionary compression? When were they added? – Buttons840 Mar 27 '11 at 05:52
  • 4
    you could use `some_dict.iteritems()` here and put `for` and `if` statements on separate lines for readability – jfs Mar 27 '11 at 05:57
  • 3
    I believe dictionary comprehensions were added in Python 2.7. – mithrandi Mar 27 '11 at 05:58
  • 2
    @J.F. Sebastian: I'm on Python 3, and `iteritems` is now `items`. In Python 2.7, `iteritems()` is indeed better. – Tim Pietzcker Mar 27 '11 at 06:00
  • 1
    @Buttons840 they are called [dict comprehensions in PEP 274](http://legacy.python.org/dev/peps/pep-0274/) or [dictionary displays](https://docs.python.org/2/reference/expressions.html#dictionary-displays). as the PEP says they were [added in 2.7](https://docs.python.org/2/whatsnew/2.7.html#python-3-1-features) as backported 3.x feats. alternatively you can feed `dict()` with an appropriate generator expression, which is 2.4. meta: can [browse the peps here](http://legacy.python.org/dev/peps/) for finding stuff out. – n611x007 May 29 '14 at 11:43
52
a = {'name': 'your_name','class': 4}
if 'name' in a: del a['name']
Kracekumar
  • 19,457
  • 10
  • 47
  • 56
42

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

Luu Tuan Anh
  • 503
  • 4
  • 8
  • 6
    However, the performance difference is not great, and if you want to avoid raising an exception, you can provide a second argument to ``pop()`` (as @n-1-1 does above) - which is not an option for the ``del`` operator. – Alex Dupuy Jul 11 '14 at 07:46
  • 1
    Ancillary to the question, but I'd also been struggling to understand `timeit`. Thank you for this clear example. – Adam_G May 01 '15 at 01:02
  • OP asked regarding when key is unknown. This answer assumes the key is known. – Jean-François Corbett Aug 08 '18 at 17:17
8

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

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.

mithrandi
  • 1,630
  • 9
  • 27
2

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

priya khokher
  • 640
  • 7
  • 14
1
y={'username':'admin','machine':['a','b','c']}
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]
Louis Kottmann
  • 16,268
  • 4
  • 64
  • 88
0

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
Nathan
  • 1
  • 1
0

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

Thane Anthem
  • 4,093
  • 4
  • 26
  • 24
  • `for k,v in d.iteritems(): del d[k]` would give `RuntimeError: dictionary changed size during iteration`. See mithrandi's explanation. – Buttons840 Mar 27 '11 at 05:59
  • 1
    Of course, d.iteritems() is not how the original poster is iterating, and not what I was referring to in my answer. – Thane Anthem Mar 27 '11 at 06:00