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.



4 Python Itertools Filter Functions You Probably Didn't Know
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 slice seq[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 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.
 


No, thanks!