Single Python loop vs multiple list comprehensions

Sometimes we need to fill multiple lists with different items based on some condition. One way to do this, that we can see online, is to use multiple list comprehensions that iterate through the same sequence, each one filtering the items by a specific, but different criteria. While this works, it raises the question why we need to iterate through the same sequence multiple times. It seems that we are both duplicating code and repeating the same operation as many times as the number of the existing list comprehensions. What if we used only a single loop that wasn't as fast as a list comprehension?

Here is the code that attempts to examine this:

from random import randint from time import perf_counter nums = [randint(0,10000) for i in range(10000000)] # Multiple list comprehensions start1 = perf_counter() a = [num for num in nums if num % 3 == 0] b = [num for num in nums if num % 3 == 1] c = [num for num in nums if num % 3 == 2] end1 = perf_counter() print('List comprehensions: ' + "{0:.4f}".format(end1 - start1)) # Single Python loop start2 = perf_counter() a, b, c = [], [], [] for num in nums: mod = num % 3 if mod == 0: a.append(num) if mod == 1: b.append(num) if mod == 2: c.append(num) end2 = perf_counter() print('Single loop: ' + "{0:.4f}".format(end2 - start2)) """ List comprehensions: 7.8951 Single loop: 10.3740 """

We see that the list comprehensions are quite compact and much more readable. But the part "for num in nums" is repeated three times and the modulo operation seems to be re-computed each time. The alternative is shown below, where we use a single Python loop, caching the result of the modulo operation in a variable. Although intuition tells us that the second version would be faster, it turns out that exactly the opposite is true. We see that on a sequence of 10 million items, the performance can vary by as much as 24%. At least on Python 3.5.2, three separate list comprehensions are still faster than a single loop implemented in Python.