DEV Community

Ryan Lee
Ryan Lee

Posted on • Updated on

Learn to be Pythonic: List of Multiples of 3

Introduction

One of the best ways to learn a programming language is by solving the same challenge with different approaches. Learning to be more Pythonic is no exception. We will solve simple Python programming challenges going from naive and straightforward ways to more Pythonic and smarter approaches. By doing so, we can gain a deeper understanding of what Python offers out of the box and appreciate the flexibility of this beautiful language.

Problem Statement

Create a list of multiples of 3 from 0 to 15 (inclusive)

Solutions

Brute Force

The simplest solution (almost like cheating) is just initializing a list with multiples of 3.

ans = [0, 3, 6, 9, 12, 15]
Enter fullscreen mode Exit fullscreen mode

While Loop with Break

Observing the problem statement, we induced that we can go through each integer i from 0 to 15, and check whether it is a multiple of 3 (i % 3 == 0). A naive implementation is to use an infinite loop (while True) and break out when i is greater than 15.

(This is inspired by a Python quiz question.)

N = 15

ans = []
i = 0
while True:
    if i % 3 == 0:
        ans.append(i)
    if i > N:
        break
    i += 1
Enter fullscreen mode Exit fullscreen mode

While Loop with Condition

A slight improvement to the above solution is to make use of the condition of the while loop: loop whenever i < N + 1.

N = 15

ans = []
i = 0
while i < N + 1:
    if i % 3 == 0:
        ans.append(i)
    i += 1
Enter fullscreen mode Exit fullscreen mode

While Loop Incremented by Steps

You may have observed that, for this particular challenge, we can reduce the number of steps by incrementing i by 3. This also eliminates the check for modulo 3.

N = 15

ans = []
i = 0
while i < N + 1:
    ans.append(i)
    i += 3
Enter fullscreen mode Exit fullscreen mode

For Loop

In fundamental computer science, when the number of iterations is known in advance, a for loop is more appropriate. A very useful iterator in Python for this use case is range.

N = 15

ans = []
for i in range(N + 1):
    if i % 3 == 0:
        ans.append(i)
Enter fullscreen mode Exit fullscreen mode

This is cleaner and more expressive than the while loop.

List Comprehension

To further refactor the solution, we turn to a feature of Python called β€œlist comprehension”. It provides a concise way to create a list from an iterator. This is when the solution starts to be more β€œPythonic”.

N = 15

ans = [i for i in range(N + 1) if i % 3]
Enter fullscreen mode Exit fullscreen mode

Filter

An alternative solution without the for loop is using the filter function. It is handy for filtering an iterator through a test function. In this example, the test function is constructed with lambda.

N = 15

ans = list(filter(lambda x: x % 3 == 0, range(N + 1)))
Enter fullscreen mode Exit fullscreen mode

Filter with Predefined Function

The lambda function is convenient but lacks context and compromises readability. A better version of the filter solution is to predefine the test function.

N = 15

def is_mul_3(x):
    return x % 3 == 0

ans = list(filter(is_mul_3, range(N + 1)))
Enter fullscreen mode Exit fullscreen mode

Range with Steps

In a previous solution, we optimized the loop by reducing the number of iterations by incrementing the counter by a step of 3. This is possible with the range function by taking advantage of its optional third argument, step. It tells range to increment the counter by the step amount. As such, we can remove the filter altogether.

N = 15

ans = list(range(0, N + 1, 3))
Enter fullscreen mode Exit fullscreen mode

Conclusion

By finding different ways to solve a simple problem, we have already touched on the key Python concepts of list, while, break, for, range, filter, lambda, and list comprehension. The earlier solutions are more naive and not recommended as best practices, but they are still good exercises to solidify the fundamentals. Between the more Pythonic list comprehension and functional style, it will require an experienced programmer to weigh the pros and cons to balance readability, efficiency, and maintainability. Lastly, using the step argument from range might seem obvious, but it requires deeper knowledge of Python and may confuse peer programmers trying to maintain the code. Therefore, it is essential for a programmer to share his or her knowledge with others, so that the team can grow as a whole, thereby increasing the efficiency (or Pythonicity?) of a software project.

Can you find other creative ways to solve this challenge?


Further resources:

  1. Python For Loop With Index
  2. When to Use a List Comprehension in Python
  3. The Python Tutorial
  4. Codewars
  5. LeetCode

Top comments (0)