# 12. Lists

• We saw that strings were a little different when compared to the other types we’ve seen (int, float, bool)

• We can generalize the idea of strings to more types

• A string is a collection of characters

• We can use lists to have a collection of other types

Activity

Run the following code:

1some_list = [5, 7, 9, 10]
2print(some_list)
3print(some_list[0])
4print(some_list[1:3])
5print(type(some_list))
1. Determine what types can be in a list.

2. Can a list contain things od different types at the same time?

3. How can you access the last element in a list?

4. Can we find the length of a list?

5. Is it possible to have a list of length 0? This would be an empty list, or a list with nothing in it.

## 12.1. Data Structures

• The list is your first real data structure

• As the name suggests, a data structure is some structure that holds data

• Lists, although simple, are exceptionally useful and important

Activity

Apply what you know about loops, strings, and lists to solve the following problems — combining algorithms and data structures is a big part of programming. Hint: You will probably find the linear searches from the strings topic to be helpful.

1. Write a function contains_while(needle, haystack) -> bool: that uses a while loop and returns True if needle is contained in the haystack and False otherwise.

2. Write a function index_of_for(needle, haystack) -> int: that uses a for loop and returns the index of needle within the haystack or -1 if it is not found.

3. Write some assert tests for both functions to verify correctness.

## 12.2. List Operators and Methods

• Similar to strings, we can concatenate lists with the + operator

1some_list = [5, 6, 7, 8, 9]
2some_other_list = ["this", "is", "a", "list"]
3bigger_list = some_list + some_other_list
4print(bigger_list)
5# Results in [5, 6, 7, 8, 9, 'this', 'is', 'a', 'list']

• We can concatenate a list with itself multiple times using the * operator

1some_list = [5, 6, 7, 8, 9]
2triple_list = some_list * 3
3print(triple_list)
4# Results in [5, 6, 7, 8, 9, 5, 6, 7, 8, 9, 5, 6, 7, 8, 9]

Activity

1. Create some list and assign it to a variable some_list

2. print out the list — print(some_list)

3. After running the code, type some_list. and wait

• Don’t forget the dot .

4. Play around with some of the methods you see

## 12.3. Mutability

• Although lists and strings have some things in common, one thing they do not have in common is mutability

• Remember, strings are immutable

• We can index strings and lists the same way to access individual elements

• But unlike strings, we can also change the elements at a specific index

1another_list = ["a", "b", "c", "d", "e"]
2another_list[2] = "X"
3print(another_list)
4# Results in ['a', 'b', 'X', 'd', 'e']

## 12.4. Lists & Loops

• Similar to how for loops made it easy to iterate over each character in a string

• for loops can be used the same way on lists to iterate over each element in the list

• for each thing in a collection of things

1collection_of_things = ["Hello", 10, True, 100.001]
2
3for thing in collection_of_things:
4  print(thing)
5
6# Results in
7#   Hello
8#   10
9#   True
10#   100.001
• Iterating over a collection of things is very common

• Expect to start using for loops like this a lot

• In fact, this was used in assignment 1 multiple times

• Iterating over the contents of the file being read

• Iterating over the list of (latitude, longitude) pairs

### 12.4.1. Range

• range is a very handy function that we often use with for loops

• It provides an easy way to loop over a specific range of numbers

1for i in range(5):
2  print(i)
3
4# Results in
5#   0
6#   1
7#   2
8#   3
9#   4
• Notice that the integer 5 was specified in the range function, and the loop ran a total of 5 times

• But because of 0 based indexing, the the number 5 is not actually included

• A big reason we like to use for loops this way is because the syntax is so simple and clean

• The above functionality can be achieved with a while loop, but the code needed is a little more cumbersome

1i = 0
2while i < 5:
3  print(i)
4  i += 1
5
6# Results in
7#   0
8#   1
9#   2
10#   3
11#   4

Activity

Write a function beer_on_wall that prints out "n bottles of beer on the wall" for all n from 99 down to 0. This function must use a for loop with the range function.

The difficulty here is the need to count backwards.

Perhaps a read of the documentation can help.

### 12.4.2. Looping Over Indices and Enumerate

• Sometimes it is important to know the indices of each element being printed out

• For example, if the goal is to do a linear search to find the index of a given element, the following would be problematic

1def index_of_uhoh(needle, haystack):
2    for element in haystack:
3        if element == needle:
4            return "????" # How do I find the index?
5    return -1
• Using the range function would help in this situation as we can use it to loop over each index in haystack

• The only catch is that we need to actually index haystack

1def index_of(needle, haystack):
2    haystack_length = len(haystack)
3    for i in range(haystack_length):
4        if haystack[i] == needle:
5            return i
6    return -1
• To make what is going on a little clearer, consider the following example

1another_list = ["a", "b", "c", "d", "e"]
2for i in range(len(another_list)):
3    print(i, another_list[i])
4
5# Results in
6#   0 a
7#   1 b
8#   2 c
9#   3 d
10#   4 e
• This loop prints out the index (i) along with the element at the given index (another_list[i])

• This functionality is quite common and Python even provides a shorthand for achieving it — enumerate

1another_list = ["a", "b", "c", "d", "e"]
2for i, element in enumerate(another_list):
3    print(i, element)
4
5# Results in
6#   0 a
7#   1 b
8#   2 c
9#   3 d
10#   4 e
• Here there is no need to actually index the list since the element variable already has the value another_list[i]