# 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`, `seq`,…, `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 slice `seq`, `seq`,..., `seq[stop - 1]`.
• If you specify the start and the stop values: `islice(seq, start, stop)` the function returns an iterator over the slice `seq[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 that `start + k*step` < `stop` and `start + (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. Get the FREE ebook 'The Great Big Natural Language Processing Primer' and the leading newsletter on AI, Data Science, and Machine Learning, straight to your inbox.  