# 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.