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.