To start this guide, download this zip file.

# List Patterns

We are going to show you some common patterns when using lists in your programs. Recognizing these patterns will help you know how to solve a problem you are given. If a problem looks like one of these, then you can follow this pattern to write your code.

## Map

The *map* pattern occurs when you want to take a list of values and individually
*map* each value in the list to a new value. Here is an example:

Original Items | New Items |
---|---|

ball | ballroom |

bath | bathroom |

bed | bedroom |

family | familyroom |

food | foodroom |

car | carroom |

Notice how we can make a new list by taking each item from the original list and concatenating ‘room’ to create a new word.

The steps for this pattern are:

- create a new, empty list
- iterate through each item in the original list
- use the item in the original list to create a new item
- append the new item to the new list

- return the new list

We can see an example of this pattern in the file called `make_rooms.py`

:

```
def make_rooms(words):
rooms = []
for word in words:
room = word + 'room'
rooms.append(room)
return rooms
if __name__ == '__main__':
some_words = ['ball', 'bath', 'bed', 'family', 'food', 'car']
rooms = make_rooms(some_words)
print(f'Original words: {some_words}')
print(f'Rooms: {rooms}')
```

Notice how we use the original list `words`

to make a new list `rooms`

. Every
word in `words`

maps to a room in `rooms`

.

You can see another example of this pattern in `smaller_numbers.py`

, which takes
a list of numbers and makes numbers smaller by dividing them by two, *keeping
only the integer portion*. To do this, you need to be sure to use the `//`

operator, which does *floor division*, meaning it works like regular division
but returns the largest possible integer that divides into numerator by the
denominator.

```
def make_smaller(numbers):
smaller_numbers = []
for number in numbers:
smaller = number // 2
smaller_numbers.append(smaller)
return smaller_numbers
if __name__ == '__main__':
original = [1, 2, 3, 4, 5, 6, 7, 8]
divided_by_two = make_smaller(original)
print(original)
print(divided_by_two)
```

## Filter

This example illustrates the *filter* pattern. By filter we mean that we start
with a list and use its values to calculate and return a *new* list that has
*some or all* of the original values. For we could take a list of numbers and
return a new list that has only the odd numbers from the original list:

Original Items | New Items |
---|---|

2 | 3 |

3 | 5 |

4 | |

5 |

The steps for this pattern are:

- create a new, empty list
- iterate through each item in the original list
- append the item to the new list if it meets some criteria

- return the new list

The file `only_odds.py`

has code for this example:

```
def only_odds(numbers: list[int]) -> list[int]:
odds = []
for number in numbers:
if (number % 2) == 1:
odds.append(number)
return odds
if __name__ == '__main__':
print(only_odds([1, 2, 3, 4, 5, 6]))
```

We start by initializing a variable `odds`

to an empty list. We then iterate
through the list and check if each number is odd. We can do this by using the
`mod`

operator, `%`

, which calculates the remainder, and check if the remainder
is zero. If it is not zero, then we have an odd number, so we can append it to
the list we store in the `odds`

variable.

The function finishes by returning `odds`

, so eventually the `print`

function
will print `[3, 5]`

.

## Select

This example illustrates the *select* pattern, which chooses a single value from
a list, such as a minimum or maximum value.

The steps for this pattern are:

- initialize a variable to store the selected value; this is set to
`None`

- iterate through the list
- if the variable is still None or the current item is “better” (smaller or
larger) than the value of the variable
- change the variable so it now has the current item

- if the variable is still None or the current item is “better” (smaller or
larger) than the value of the variable
- return the variable

The file called `find_min.py`

has an example:

```
def find_min(numbers: list[int]) -> int:
smallest = None
for number in numbers:
if smallest is None or number < smallest:
smallest = number
return smallest
if __name__ == '__main__':
print(find_min([3, 6, 2, 8, 1, 7]))
```

Here we are trying to calculate the minimum value of a list of numbers. We start
by initializing `smallest`

to `None`

, because there is no smallest number yet.
Then, when we iterate over the list, we do *two* checks with an `if`

statement.
First, we check if smallest is still `None`

. If it is, that means we haven’t
found a smallest number yet, so the one we are currently looking at must be the
smallest. Second, we check if the current `number`

is smaller than `smallest`

.
If either of these checks succeeds, we set `smallest = number`

.

Here is a chart for the iterations of the loop:

Iteration | number | smallest |
---|---|---|

0 | N/A | None |

1 | 10 | 10 |

2 | 8 | 8 |

3 | 40 | 8 |

4 | 22 | 8 |

5 | 3 | 3 |

6 | 5 | 3 |

At the end, `smallest = 3`

.

Notice that if we ran this code:

`result = find_min([])`

then we would get `result = None`

.

## Accumulate

This example demonstrates the *accumulate* pattern. By accumulate, we mean
calculating a single value as we iterate, like taking a sum or an average.

The steps for this pattern are:

- initialize a variable to an appropriate value (for example, zero)
- iterate through the list
- use the new item to modify the variable (for example, add it to the variable or subtract it)

- return the variable

The file `average.py`

contains an example:

```
def average(numbers: list[int]) -> float:
total = 0
for number in numbers:
total = total + number
return total / len(numbers)
if __name__ == '__main__':
print(average([1, 2, 3, 4]))
```

In the `average()`

function, we initialize the `total`

variable to zero. Then,
each time we iterate through the numbers, we increase total by the current
number. We finally return the total divided by the length of the list.

Here is a chart showing how this code updates the `number`

and `total`

variables
each time through the loop. Iteration number 0 is where we start before the
`for`

loop.

Iteration | number | total |
---|---|---|

0 | N/A | 0 |

1 | 1 | 1 |

2 | 2 | 3 |

3 | 3 | 6 |

4 | 4 | 10 |

At the end of the function, it returns `total / 4`

, which is `2.5`

.

## Multiple patterns at once

Here is a problem that requires using multiple patterns: given a list of numbers, write a function that subtracts 7 and then removes any negative numbers and any numbers greater than 10.

There is starter code in `all_together.py`

:

```
def make_it_happen(numbers: list[int]) -> list[int]:
# Write code here
pass
if __name__ == '__main__':
original = [0, 7, 2, 14, 20, 32, 5, 12]
changed = make_it_happen(original)
print(changed)
```

How would you solve this problem? Focus on the functions you would call in
`make_it_happen()`

.

Here is one idea of how to do this:

```
def make_it_happen(numbers: list[int]) -> list[int]:
numbers = sub_7(numbers)
numbers = filter_numbers(numbers)
return numbers
```

We create two functions — one to do the subtraction (which should use the map pattern) and one to do the filtering.

We can implement `sub_7()`

first:

```
def sub_7(numbers: list[int]) -> list[int]:
new = []
for number in numbers:
new.append(number - 7)
return new
```

This follows the *map* pattern. Notice that we do the mapping and appending all
in one step with `new.append(number - 7)`

.

We can temporarily use an empty function for `filter_numbers()`

. Since this
function needs to return something, we can do this with:

```
def filter_numbers(numbers: list[int]) -> list[int]:
return numbers
```

That just returns the original list unchanged. Now we can run our program, which starts with:

`nums = [0, 7, 2, 14, 20, 32, 5, 12]`

We get the following printed out:

`[-7, 0, -5, 7, 13, 25, -2, 5]`

That looks good!

Now we can implement filtering:

```
def should_keep(number: int) -> bool:
return number >= 0 and number <= 10
def filter_numbers(numbers: list[int]) -> list[int]:
new = []
for number in numbers:
if should_keep(number):
new.append(number)
return new
```

Notice that we use a separate function `should_keep()`

to implement the decision
about whether to keep a number in the list. We can do this with
`number >= 0 and number <= 10`

. We phrased this problem as *removing any
negative numbers and any numbers greater than 10*, but for filtering we need to
turn that into a statement about which numbers to keep: *keeping all numbers
greater than or equal to zero and less than or equal to 10*.

Now when we run our code we get:

`[0, 7, 5]`

This has kept all of the numbers between and including 0 and 10.