# List Comprehensions

List comprehensions provide a concise way to create lists.

### Comparison of Multi-line Program Versus List Comprehension

Here's a simple example in which we create a new list of squares.

We'll loop over this list below.

```list(range(1, 5))
```
```[1, 2, 3, 4]
```

In Python, we can iterate over just `range(1, 5)` to iterate over `1` through `4` including the value `4`.

`range(1, 5)` gives us an immutable sequence. We can iterate over it but we cannot simply index a value from it.

```small_range = range(1, 5)
```

Each number in the list will put to the power of 2, otherwise called number squared.

number squared operation number squared
1 12 1
2 22 4
3 32 9
4 42 16

Our result should be a list: `[1, 4, 9, 36]`

#### Multi-line program

```squares = []
for number in small_range:
squares.append(number**2)
```
```squares
```
```[1, 4, 9, 16]
```

#### List comprehension

A list comprehension consists of brackets `[]` containing an expression followed by a `for` clause.

```[number**2 for number in small_range]
```
```[1, 4, 9, 16]
```

We can assign a variable to the result of this list comprehension.

```squares_again = [number**2 for number in small_range]
```
```squares_again
```
```[1, 4, 9, 16]
```

### Additional Simple List Comprehension Examples

You can also use any number of `if` clauses in a list comprehension.

We can create a new list to remove all mentions of the name `dan`.

```names = ['sean', 'dan', 'bill', 'jamie', 'dan']
```
```names_without_dan = [name for name in names if name!='dan']
```
```names_without_dan
```
```['sean', 'bill', 'jamie']
```

Similar to our initial example of creating squares of numbers, we can use a list comprehension to create a list of tuples with each tuple a pair of a value and its square.

```[(number, number**2) for number in range(1, 5)]
```
```[(1, 1), (2, 4), (3, 9), (4, 16)]
```

### Measuring the Performance of List Comprehensions

Often times, using list comprehensions over traditional multi-line programs can result in code that executes in a shorter period of time. This is especially useful if you're doing operations on large datasets.

We'll mimic the example above with the only difference being we'll iterative over all numbers from `1` to `12000000` - that's 1.2 million operations!

In Jupyter Notebooks, we can use `%%time` to measure the runtime of code blocks.

```big_range = range(1, 12000001)
```

#### Multi-line program

```%%time

many_squares = []
for number in big_range:
many_squares.append(number**2)
```
```CPU times: user 5.33 s, sys: 284 ms, total: 5.62 s
Wall time: 5.64 s
```

#### List Comprehension

```%%time

many_squares_again = [number**2 for number in big_range]
```
```CPU times: user 3.98 s, sys: 259 ms, total: 4.24 s
Wall time: 4.25 s
```

This list comprehension takes over 25% less time to compute than the multi-line program.

Performance results of list comprehensions vary. Sometimes, your program will run in significantly less time; other time, runtime may be on part with a multi-line program.

I'd encourage you to try both in your programs to see what works best.