avatarYang Zhou

Summary

The undefined website article discusses ten powerful Python itertools functions that enhance code efficiency and readability by simplifying complex looping logic, iterable manipulation, and data processing tasks.

Abstract

The article "10 Python Itertools To Make Your Code Neater, Cleaner, and Better" emphasizes the utility of the itertools module in Python for writing concise and efficient code. It introduces functions like product() for avoiding nested loops, compress() for filtering data, and groupby() for grouping iterable elements. The module also provides combinations() and permutations() for generating set-theoretic combinations and permutations, respectively. Functions like accumulate() facilitate the creation of accumulated values, while repeat(), cycle(), and count() generate infinite iterables for various use cases. The article also highlights newer additions like pairwise() for creating overlapping pairs and takewhile() and dropwhile() for conditional filtering of elements. The author advocates for leveraging these tools to improve code quality and maintainability.

Opinions

  • The author believes that Python's simplicity is not only due to its syntax but also its powerful built-in modules like itertools.
  • The use of itertools is encouraged for making Python code more "Pythonic" by reducing the complexity of loops and conditional statements.
  • The article suggests that using itertools can significantly reduce the amount of code needed to perform common iterable manipulations.
  • The author implies that understanding and utilizing itertools can be a mark of programming proficiency in Python.
  • There is an appreciation for the itertools module's ability to handle both finite and infinite iterables, showcasing its versatility.
  • The author's inclusion of practical examples for each function indicates a preference for learning through application and demonstrates the immediate usefulness of the module in real-world scenarios.
  • By providing a link to a related article on iterables and iterators, the author suggests that readers should have a foundational understanding of these concepts to fully appreciate the power of itertools.

10 Python Itertools To Make Your Code Neater, Cleaner, and Better

Implement the same thing with shorter code

Image from Wallhaven

The beauty of Python lies in its simplicity.

Not only because Python’s syntax is elegant, but also due to it has many well-designed built-in modules that help us implement common functionalities efficiently.

The itertools module, which is a good example, provides many powerful tools for us to manipulate Python iterables in shorter code.

Do more by less. This is what you can get from the itertools module. Let’s check it out from this article.

1. itertools.product(): A Tricky Way To Avoid Nested Loops

When a program becomes more and more complicated, you may need to write nested loops. At the same time, your Python code will become ugly and unreadable:

list_a = [1, 2020, 70]
list_b = [2, 4, 7, 2000]
list_c = [3, 70, 7]

for a in list_a:
    for b in list_b:
        for c in list_c:
            if a + b + c == 2077:
                print(a, b, c)
# 70 2000 7

How to make the above code Pythonic again?

The itertools.product() function is your friend:

from itertools import product

list_a = [1, 2020, 70]
list_b = [2, 4, 7, 2000]
list_c = [3, 70, 7]

for a, b, c in product(list_a, list_b, list_c):
    if a + b + c == 2077:
        print(a, b, c)
# 70 2000 7

As demonstrated above, it returns the Cartesian product of input iterables, which helps us put 3 nested for loops into one.

2. itertools.compress(): A Convenient Way To Filter Data

We can filter a list of items through one or a few loops for sure.

But sometimes, we may not need to write any loops. Cause there is a function named itertools.compress().

The itertools.compress() function returns an iterator that filters an iterable based on the values of a corresponding boolean mask.

For example, the following code selects the true leaders using the itertools.compress() function:

import itertools
leaders = ['Yang', 'Elon', 'Tim', 'Tom', 'Mark']
selector = [1, 1, 0, 0, 0]
print(list(itertools.compress(leaders, selector)))
# ['Yang', 'Elon']

The second argument, selector, works as a mask, we can also define it as follows:

selector = [True, True, False, False, False]

3. itertools.groupby(): Group Elements of an Iterable

The itertools.groupby() function is a convenient way to group adjacent duplicate items of an iterable.

For instance, we can group a long string as follows:

from itertools import groupby

for key, group in groupby('YAaANNGGG'):
    print(key, list(group))
# Y ['Y']
# A ['A']
# a ['a']
# A ['A']
# N ['N', 'N']
# G ['G', 'G', 'G']

Furthermore, we can harness its second argument to tell the groupby() function how to determine whether two items are the same or not:

from itertools import groupby

for key, group in groupby('YAaANNGGG', lambda x: x.upper()):
    print(key, list(group))
# Y ['Y']
# A ['A', 'a', 'A']
# N ['N', 'N']
# G ['G', 'G', 'G']

4. itertools.combinations(): Get All Combinations of a Given Length From an Iterable

It needs a beginner a while to write a bug-free function to get all possible combinations of a list.

In fact, if she knows the itertools.combination() function, she can get it easily:

import itertools

author = ['Y', 'a', 'n', 'g']

result = itertools.combinations(author, 2)

for x in result:
    print(x)
# ('Y', 'a')
# ('Y', 'n')
# ('Y', 'g')
# ('a', 'n')
# ('a', 'g')
# ('n', 'g')

As the above program shows, the itertools.combination() function has two parameters, one is the original iterable, and the other is the length of the subsequences that will be generated by the function.

5. itertools.permutations(): Get All Permutations of a Given Length From an Iterable

Since there is a function to get all combinations, of course, there is another function named itertools.permutations to get all possible permutations:

import itertools

author = ['Y', 'a', 'n', 'g']

result = itertools.permutations(author, 2)

for x in result:
    print(x)

# ('Y', 'a')
# ('Y', 'n')
# ('Y', 'g')
# ('a', 'Y')
# ('a', 'n')
# ('a', 'g')
# ('n', 'Y')
# ('n', 'a')
# ('n', 'g')
# ('g', 'Y')
# ('g', 'a')
# ('g', 'n')

As shown above, the use of itertools.permutations() function is similar as the itertools.combinations(). The only difference is their results.

6. itertools.accumulate(): Generate Accumulated Items from an Iterable

Getting a series of accumulated values based on an iterable is a common requirement. With the help of the itertools.accumulate() function, we don’t need to write any loops to implement.

import itertools
import operator

nums = [1, 2, 3, 4, 5]
print(list(itertools.accumulate(nums, operator.mul)))
# [1, 2, 6, 24, 120]

The above program is the same as follows if we wouldn't like to use the operator.mul:

import itertools

nums = [1, 2, 3, 4, 5]
print(list(itertools.accumulate(nums, lambda a, b: a * b)))
# [1, 2, 6, 24, 120]

7. itertools.repeat(), itertools.cycle(), itertools.count(): Make Infinite Iterables

In some cases, we need to get an infinite iterable. There are 3 functions that are helpful:

itertools.repeat(): Generate the same item repeatedly

For example, we can get three same “Yang” as follows:

import itertools
print(list(itertools.repeat('Yang', 3)))
# ['Yang', 'Yang', 'Yang']

itertools.cycle(): Get an infinite iterator by cycling

The itertools.cycle function will not stop until you break the loop:

import itertools

count = 0

for c in itertools.cycle('Yang'):
    if count >= 12:
        break
    else:
        print(c, end=',')
        count += 1
# Y,a,n,g,Y,a,n,g,Y,a,n,g,

itertools.count(): generate an infinite sequence of numbers

If all we need is numbers, use the itertools.count function:

import itertools

for i in itertools.count(0, 2):
    if i == 20:
        break
    else:
        print(i, end=" ")
# 0 2 4 6 8 10 12 14 16 18

As illustrated above, its first parameter is the starting number, and the second parameter is the step.

8. itertools.pairwise(): Get Tuples of Pairs Easily

Since Python 3.10, the itertools module has a new function named pairwise. It is a small and neat tool to generate successive overlapping pairs from an iterable.

import itertools

letters = ['a', 'b', 'c', 'd', 'e']

result = itertools.pairwise(letters)

print(list(result))
# [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e')]

9. itertools.takewhile(): Filter Elements in a Different Way

itertools.takewhile() returns an iterator that generates elements from an iterable as long as a given predicate function evaluates to True.

import itertools

nums = [1, 61, 7, 9, 2077]

print(list(itertools.takewhile(lambda x: x < 100, nums)))
# [1, 61, 7, 9]

This function is different from the built-in filter() function.

The filter function will go through the whole list:

nums = [1, 61, 7, 9, 2077]

print(list(filter(lambda x: x < 10, nums)))
# [1, 7, 9]

However, the itertools.takewhile function, as its name implies, will stop when the evaluating function is False:

import itertools

nums = [1, 61, 7, 9, 2077]

print(list(itertools.takewhile(lambda x: x < 10, nums)))
# [1]

10. itertools.dropwhile(): A Reverse Operation of itertools.takewhile()

This function seems like a reverse idea of the previous one.

The itertools.takewhile() returns the elements of the iterable as long as the predicate function is True, whereas itertools.dropwhile() drops the elements of the iterable as long as the predicate function is True and then returns the remaining elements.

import itertools

nums = [1, 61, 7, 9, 2077]

print(list(itertools.dropwhile(lambda x: x < 100, nums)))
# [2077]

Thanks for reading. ❤️

If you like it, please follow me to enjoy more articles about programming and technologies.

Reference:

Programming
Python
Coding
Data Science
Software Development
Recommended from ReadMedium