Loop Alternatives

Loops in Python are very slow. Nested loops are especially slow. Some alternatives are available in the standard set of packages that are usually faster..

List Comprehensions

A list comprehension collapses a loop over a list and, optionally, an if clause.

squares=[x**2 for x in range(10)]

This is equivalent to

squares=[]
for x in range(10):
    squares.append(x**2)

With an optional conditional it becomes

positives=[math.sqrt(x) for x in range(-10,11) if x>0]

This is equivalent to

for x in range(-10,11):
    if x>0:
        positives.append(math.sqrt(x))

List comprehensions may be nested.


list_2d = [[i+j for j in range(1,6)] for i in range(10,16)]

Observe the ordering in the previous example. The inner loop is first.

Exercise

Use math.sin and list comprehensions to generate a list of the sines of the numbers from -1.0 to 1.0 inclusive with an increment of 0.1. Print the result as a table of x, sin(x) using a for loop.

Example solution

import math
xs=[0.1*float(x) for x in range(-10,11)]
sines=[math.sin(x) for x in range(-10,11)]
for i,x in enumerate(xs):
    print(x, sines[i])

Functionals

A functional in this context is a function that takes a function as its argument. Python has functionals that can take the place of loops.

Map/Reduce/Filter

The map functional applies a function individually to each element of an iterable and returns an iterator (in Python 3). Since we frequently want to do something with the result we can cast it to a list.

float_vals=list(map(float,range(20)))
print(float_vals)

Map is said to broadcast the function across the iterable.

The reduce function takes a binary (two arguments) function and applies it pairwise to each element, working its way down the iterable, to produce a single result. It was removed from core Python in Python 3 but can be imported from the functools module.

from functools import reduce
def adder(x,y):
   return x+y
sum_it=reduce(adder,range(20))
print(sum_it)

The filter functional takes a function that returns a Boolean (True or False) and applies it elementwise to the iterable, returning an iterator.

def is_even(n):
   return n%2==0
evens=list(filter(is_even,range(21)))
print(evens)

Map, filter, and reduce are frequently used with lambda functions.

NumPy

Another way to avoid for loops is to use NumPy. The best speedups are usually achieved when it is possible to use NumPy built-in “vectorized” functions. For more details, see our workshop on High-Performance Python.

Previous
Next