 Computer Science

# 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 ItemsNew Items
ballballroom
bathbathroom
bedbedroom
familyfamilyroom
foodfoodroom
carcarroom

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 ItemsNew Items
23
35
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):
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
• return the variable

The file called `find_min.py` has an example:

``````def find_min(numbers):
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:

Iterationnumbersmallest
0N/ANone
11010
288
3408
4228
533
653

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):
total = 0
for number in numbers:
total = total + number

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.

Iterationnumbertotal
0N/A0
111
223
336
4410

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):
# 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):
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):
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):
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):
return number >= 0 and number <= 10

def filter_numbers(numbers):
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.