Filtering Dictionary In Python 3

1*SgfSI1rlQ8qNlgJYoBLP1g.png

“RuntimeError: Dictionary changed size during iteration”, Python slaps you in your face when you try to add/remove entries in dict object during iteration.

In this post, I will walk us through how we can filter a dict collection. First, let us try to understand the problem by running this snippet in your interpreter:

Try to run this snippet!

You will get a RuntimeError, as expected.

1*DQYkA73-GHxjfo2yJi6qPA.png

“RuntimeError: dictionary changed size during iteration”, Python interpreter

The error message is self-explanatory and this makes perfect sense, you shouldn’t be able to expand/shrink the collection while you are looping through it. Imagine if you are allowed to do so, and you keep expanding the collection in your loop body:

If the above snippet is valid in Python, we will slump into infinite loop until memory is run out.

So, in any event we want to filter a dict object in Python, can we circumvent away from the RuntimeError? Of course!

Possible Solutions

Solution #1: Use A Shallow Copy

This is the least favorable solution, given that we have to create a new copy of the dictionary.

The above code will work, but it’s less hygienic to me.

Solution #2: Use A Copy Of Dictionary Keys

Another solution is instead, create a copy of dictionary keys as our iterator:

Solution #3: Deferred Update

If you are against of create any copy of either the source dictionary or the keys, we can also use the “deferred update” strategy. Deferred update, as the name tells, is to defer any mutation to the dictionary until the iteration is over.

However, a caveat here. Imagine an uncaught exception in between line 9 and 10, the iteration will break, all pending updates will be void and your dict object will be left intact.

I personally in favor of using copy of dictionary keys anddeferred update. In the subsequent part of this post, I will use the former to illustrate how we can make our filter logic reusable.

Making The Logic Reusable

At this point, I decided to use a copy of dictionary keys to mitigate the problem when attempting to delete entries during iteration. Let’s see how we can make the logic reusable.

In my case, I created FilterableDict — a subclass of the built-in dict class to add filter() method:

FilterableDict, subclass of built-in dict class

To further reduce the memory footprint of our key copy, I use a tuple instead of a list collection to store them.

Let’s make use of our FilterableDict and observe the output:

1*EEm54OcZDEOD7Laj9AomQA.png

Using our FilterableDict

Here we go, a reusable class to support filtering for a dictionary in Python.

Full Source Code:

Final Words

A different way to achieve the same purpose? Leave me a comment :)

First published on 2019-07-01

Republished on Hackernoon

Comments (1)

Seth Livingston's photo

Try the same operation using a dict comprehension; I think you'll like the result. :)