4 Python Itertools Filter Functions You Probably Didn’t Know
And why you should learn how to use them to filter Python sequences more elegantly.
Image by Author
In Python, iterators help you write more Pythonic code—and work more efficiently—with long sequences. The built-in itertools module provides several helpful functions that create iterators.Â
These are especially helpful when you want to just loop through the iterator, retrieve elements in the sequence, and process them—all without having to store them in memory. Today we’ll learn how to use the following four itertools filter functions:
- filterfalse
- takewhile
- dropwhile
- islice
Let's get started!
Before You Begin: A Note on Code Examples
In this tutorial:
- All the four functions that we’ll discuss give iterators. For clarity, we’ll work with simple sequences and use
list()
to get a list containing all the elements returned by the iterator. But refrain from doing so—unless necessary—when working with long sequences. Because when you do so, you’ll lose the memory savings that iterators give you. - For simple predicate functions, you can also use lambdas. But for better readability, we’ll define regular functions and use them as predicates.
1. filterfalse
If you’ve been programming in Python for a while, you’ll have likely used the built-in filter
function with the syntax:
filter(pred,seq)
# pred: predicate function
# seq: any valid Python iterable
The filter
function gives an iterator that returns elements from the sequence for which the predicate returns True
.
Let’s take an example:
nums = list(range(1,11)) #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def is_even(n):
return n % 2 == 0
Here, the nums
list and is_even
function are the sequence and the predicate, respectively.Â
To get the list of all even numbers in nums
, we use the filter
as shown:
nums_even = filter(is_even, nums)
print(list(nums_even))
Output >>> [2, 4, 6, 8, 10]
Now let’s learn about filterfalse
. We’ll import the filterfalse
function (and all other functions that we’ll discuss) from the itertools module.
As the name suggests, filterfalse
does the opposite of what the filter
function does. It gives an iterator that returns elements for which the predicate returns False
. Here’s the syntax to use the filterfalse
function:
from itertools import filterfalse
filterfalse(pred,seq)
The function is_even
returns False
for all odd numbers in nums
. So the nums_odd
list obtained using filterfalse
is the list of all odd numbers in nums
:
from itertools import filterfalse
nums_odd = filterfalse(is_even, nums)
print(list(nums_odd))
Output >>> [1, 3, 5, 7, 9]
2. takewhile
The syntax to use the takewhile
function is:
from itertools import takewhile
takewhile(pred,seq)
The takewhile
function gives an iterator that returns elements so long as the predicate function returns True
. It stops returning elements when the predicate returns False
for the first time.Â
For an n-length sequence, if seq[k]
is the first element for which the predicate function returns False
, then the iterator returns seq[0]
, seq[1]
,…, seq[k-1]
.
Consider the following nums
list and predicate function is_less_ than_5
. We use the takewhile
function as shown:
from itertools import takewhile
def is_less_than_5(n):
return n < 5
nums = [1, 3, 5, 2, 4, 6]
filtered_nums_1 = takewhile(is_less_than_5, nums)
print(list(filtered_nums_1))
Here, the predicate is_less_than_5
returns False
—for the first time—for the number 5:
Output >>> [1, 3]
3. dropwhile
Functionally, the dropwhile
function does the opposite of what the takewhile
function does.Â
Here's how you can use the dropwhile
function:
from itertools import dropwhile
dropwhile(pred,seq)
The dropwhile
function gives an iterator that keeps dropping elements—so long as the predicate is True
. Meaning the iterator does not return anything until the predicate returns False
for the first time. And once the predicate returns False
, the iterator returns all the subsequent elements in the sequence.Â
For an n-length sequence, if seq[k]
is the first element for which the predicate function returns False
, then the iterator returns seq[k]
, seq[k+1]
,…, seq[n-1]
.
Let’s use the same sequence and predicate:
from itertools import dropwhile
def is_less_than_5(n):
return n < 5
nums = [1, 3, 5, 2, 4, 6]
filtered_nums_2 = dropwhile(is_less_than_5, nums)
print(list(filtered_nums_2))
Because the predicate function is_less_than_5
returns False
—for the first time—for the element 5, we get all the elements of the sequence starting from 5:
Output >>> [5, 2, 4, 6]
4. islice
You’ll already be familiar with slicing Python iterables like lists, tuples, and strings. Slicing takes the syntax: iterable[start:stop:step]
.
However, this approach of slicing has the following drawbacks:
- When working with large sequences, each slice or subsequence is a copy that takes up memory. This can be inefficient.
- Because the step can also take negative values, using the start, stop, and step values affects readability.
The islice
function addresses the above limitations:
- It returns an iterator.
- It doesn’t allow negative values for the step.
You can use the islice
function like so:
from itertools import islice
islice(seq,start,stop,step)
Here are a few different ways you can use the islice
function:
- Using
islice(seq, stop)
returns an iterator over the sliceseq[0]
,seq[1]
,...,seq[stop - 1]
. - If you specify the start and the stop values:
islice(seq, start, stop)
the function returns an iterator over the sliceseq[start]
,seq[start + 1]
,...,seq[start + stop - 1]
. - When you specify the start, stop, and step arguments, the function returns an iterator over the slice
seq[start]
,seq[start + step]
,seq[start + 2*step]
,...,seq[start + k*step]
. Such thatstart + k*step
<stop
andstart + (k+1)*step
>=stop
.
Let’s take an example list to understand this better:
nums = list(range(10)) #[0,1, 2, 3, 4, 5, 6, 7, 8, 9]
Now let's use the islice
function with the syntax we have learned.
Using Only the Stop Value
Let’s specify only the stop index:
from itertools import islice
# only stop
sliced_nums = islice(nums, 5)
print(list(sliced_nums))
And here’s the output:
Output >>> [0, 1, 2, 3, 4]
Using the Start and Stop Values
Here, we use both the start and stop values:
# start and stop
sliced_nums = islice(nums, 2, 7)
print(list(sliced_nums))
The slice starts at index 2 and extends up to but not including index 7:Â
Output >>> [2, 3, 4, 5, 6]
Using the Start, Stop, and Step Values
When we use the start, stop, and step values:
# using start, stop, and step
sliced_nums = islice(nums, 2, 8, 2)
print(list(sliced_nums))
We get a slice starting at index 2, extending up to but not including index 8, with a step size of 2 (returning every second element).
Output >>> [2, 4, 6]
Wrapping Up
I hope this tutorial helped you understand the basics of itertools filter functions. You’ve seen some simple examples to understand the working of these functions better. Next, you can learn how generators generator functions and generator expressions work as efficient python iterators.
Bala Priya C is a developer and technical writer from India. She likes working at the intersection of math, programming, data science, and content creation. Her areas of interest and expertise include DevOps, data science, and natural language processing. She enjoys reading, writing, coding, and coffee! Currently, she's working on learning and sharing her knowledge with the developer community by authoring tutorials, how-to guides, opinion pieces, and more.