13. Lists#
In our lives, we regularly use lists - things to buy, stuff to do, etc. As we use those lists, we add items, we remove items, and we change items.
Python provides a list data type. Lists are ordered sequences of items. Unlike arrays in other programming languages, lists can contain items (objects, elements) of different types.
Lists are the first example of data structures that we will see in these notebooks. Data structures provide a way to organize a collection of data values, relationships among those values, and operations(functions) that can be applied to the values or the collection as a whole.
For example, assume we have a shopping list:
bread
milk
colby cheese
sliced turkey meat
A list provides a way to organize those four items into a single unit. Within a list, the items are ordered so they appear and can be accessed in that manner - this provides the relationships. We then have operations to remove an element, clear the entire list, sort the list, etc.
To define a list, use a comma separated list of zero or more values between square brackets.
1empty_list = []
2another_empty_list = list()
3primes = [1,2,3,5,7,11,13,17,19]
4acc_schools = ["Duke", "Notre Dame", "UNC", "NCSU", "Wake Forest", "Clemson"]
5mixed_list = [ "school", 1842, "test", "April", 5.4]
Unlike numbers and strings, lists are mutable objects. That is, we can add and remove items from a list and we still have the same reference to the list.
13.1. Indexing and Slicing#
As lists are sequences, we can use the same operations we used on strings to get the length, indexing, and slicing.
1print("len(acc_schools):", len(acc_schools))
len(acc_schools): 6
1print("acc_schools[0]:",acc_schools[0])
2print("acc_schools[-1]:",acc_schools[-1])
acc_schools[0]: Duke
acc_schools[-1]: Clemson
1print("acc_schools[:3]:",acc_schools[:3])
acc_schools[:3]: ['Duke', 'Notre Dame', 'UNC']
13.2. Adding to a list#
The + operation (concatenation) creates a new list by combining two lists.
1print(id(acc_schools))
2new_list = acc_schools + ["Miami"]
3print(new_list)
4print(id(new_list))
4429910656
['Duke', 'Notre Dame', 'UNC', 'NCSU', 'Wake Forest', 'Clemson', 'Miami']
4429904832
1new_list = acc_schools + "Virginia" # Raises a TypeError
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[6], line 1
----> 1 new_list = acc_schools + "Virginia" # Raises a TypeError
TypeError: can only concatenate list (not "str") to list
Calling the append() method will add an item to the end of the existing list.
1new_list.append("Virginia")
2print(new_list)
3print(id(new_list))
['Duke', 'Notre Dame', 'UNC', 'NCSU', 'Wake Forest', 'Clemson', 'Miami', 'Virginia']
4429904832
As you can see from the IDs, new_list is still the same object, but we have added “Virginia” to the list using append(). However, the list concatenation using the + operator produces a new object.
You can also add items to a list with the extend() method. This method treats the argument as a sequence and iterates through that sequence, adding each item to the list.
Try adding Pittsburgh to new_list using extend():
1# Add "Pittsburgh" to new list and print the result
2
3print(new_list)
['Duke', 'Notre Dame', 'UNC', 'NCSU', 'Wake Forest', 'Clemson', 'Miami', 'Virginia']
Did you expect that result?
If 'P', 'i', 't', 't', 's', 'b', 'u', 'r', 'g', 'h' appeared in the list, remember strings are sequences, so extend() iterated through the sequence, adding each element to new_list.
Usually to use extend(), put the term into a list (or use an existing list) and then make the call.
1# Add "Pittsburgh" to new list and print the result
2
3print(new_list)
['Duke', 'Notre Dame', 'UNC', 'NCSU', 'Wake Forest', 'Clemson', 'Miami', 'Virginia']
What happens if we pass a list to append()?
1new_list.append(["Florida State"])
2print(new_list)
['Duke', 'Notre Dame', 'UNC', 'NCSU', 'Wake Forest', 'Clemson', 'Miami', 'Virginia', ['Florida State']]
The last element should be a list itself; collection objects such as lists can be nested within each other.
Use insert(index, value) to put an item at a specific index in the list.
For practice, insert “Miami” at the start of the acc_schools list.
1# add a line of code to put Miami at the start of the acc_schools list
2
3print(acc_schools)
['Duke', 'Notre Dame', 'UNC', 'NCSU', 'Wake Forest', 'Clemson']
Now, put “Pittsburgh” into the list at the 6th position (i.e., between “NCSU” and “Wake Forest”). Remember, indexes start at zero.
1# add a line of code to put Pittsburgh at the 6th position
2
3print(acc_schools)
['Duke', 'Notre Dame', 'UNC', 'NCSU', 'Wake Forest', 'Clemson']
13.3. Removing from a list#
list.pop()removes an item from the end of the list, returning that valuelist.pop(index)removes an item at the specific index in the list, returning that value. Uselist.pop(0)to remove and return the first item in the list.del list[index]removes an item at the specified index
1last = acc_schools.pop() # Removes the last element
2first = acc_schools.pop(0) # Removes the first element
3print(first)
4print(last)
5print(acc_schools)
Duke
Clemson
['Notre Dame', 'UNC', 'NCSU', 'Wake Forest']
Use list.remove(value) to remove a specific value from the list. Only the first found match is removed. No value is returned. The method raises a ValueError if there is no such item.
Remove “UNC” from acc_schools:
1# Add the line remove the value "UNC"
2
3print(acc_schools)
['Notre Dame', 'UNC', 'NCSU', 'Wake Forest']
To empty a list, use clear()
1acc_schools.clear()
2print(acc_schools)
[]
13.4. Searching for Values#
To count the number of times a value exists in a list, use count(value).
1acc_schools = ["Duke", "Notre Dame", "UNC", "NCSU", "Wake Forest", "Clemson","Duke"]
2acc_schools.count("Duke")
2
To test if a value exists in a list, use the in operator.
1print("ND" in acc_schools)
False
1school = "NCSU"
2print(school in acc_schools)
True
To find the first index where an item occurs in a list, use index(value). The method raises a ValueError if the value does not exist in the list. Optionally, you can specify start and end indexes to limit the search.
1acc_schools.index("Duke")
0
1acc_schools.index("Duke",1,len(acc_schools)) # starts checking at the second element in the list
6
1acc_schools.index("Duke",2,5) # Raises a ValueError - Duke isn't in the specified raange of the list
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[21], line 1
----> 1 acc_schools.index("Duke",2,5) # Raises a ValueError - Duke isn't in the specified raange of the list
ValueError: 'Duke' is not in list
13.5. Sorting#
To sort a list, use the sort() method, which orders the list by lexicographical order. Add the argument reverse=True to sort in reverse order
1acc_schools.sort()
2print(acc_schools)
['Clemson', 'Duke', 'Duke', 'NCSU', 'Notre Dame', 'UNC', 'Wake Forest']
Now sort the list in descending order.
1# Sort acc_schools in descending order by adding the necessary statement with an argument
2
3print(acc_schools)
['Clemson', 'Duke', 'Duke', 'NCSU', 'Notre Dame', 'UNC', 'Wake Forest']
Python offers the built-in function sorted() to sort iterables such as lists. This function returns a new list. In addition, you can add the argument reverse=True to sort in descending order.
1sorted_schools = sorted(acc_schools)
2sorted_schools
['Clemson', 'Duke', 'Duke', 'NCSU', 'Notre Dame', 'UNC', 'Wake Forest']
Use the id() function to show that acc_schools and sorted_schools are two different objects
1# print the id values for acc_schools and sorted schools
Now try to pass a string to sorted(). What was the result? Why did this happen?
1x = sorted("hello")
2print(x)
['e', 'h', 'l', 'l', 'o']
A string is a sequence, so sorted processed that sequence of items into sorted order.
What happens when you try to sort a list with a mixture of different types? Try sorting mixed_list that we defined earlier.
1# Add code to sort mixed_list
13.5.1. sort() vs sorted()#
Another difference between these two functions is that sort() does its work “in-place” and returns None. In other words, it sorts the contents using the existing list. As we get into objects, sort() is a method on a list object and the method alters the state of that list object.
sorted() is a built-in Python function that returns a new list object as its result.
13.6. Reversing#
To reverse the current order of a list, use reverse()
1acc_schools.reverse()
2acc_schools
['Wake Forest', 'UNC', 'Notre Dame', 'NCSU', 'Duke', 'Duke', 'Clemson']
13.7. Copying#
To perform a shallow copy of a list, use copy(). With a shallow copy, we have a new list object with the same contents as the current list. However, those contents are the same - in other words, only the references have been copied into the new list.
This is the same as using the slice operation: list [:]
1acc_schools = [["Duke", "UNC", "NCSU"], "Notre Dame", "Wake Forest"]
2new_list = acc_schools.copy()
3new_list
4
5# now see what heppens to both lists if we delete an element from the "sublist"
6new_list[0].pop()
7print(acc_schools)
8print(new_list)
[['Duke', 'UNC'], 'Notre Dame', 'Wake Forest']
[['Duke', 'UNC'], 'Notre Dame', 'Wake Forest']
You should view this execution on PythonTutor.com.
As you can see from that website, we now have two “base” lists, but the first element in both lists references the same list that contains the Research Triangle universities.
We can also perform a deep copy of a list. A deep copy will construct a new list and then recursively create new copies of each element of the original list, placing that new copy into the new list. (We cover recursion in more detail in later notebooks.) We will want to use deep copy when our collection (e.g., a list or dictionary) contains other collections.
To perform a deep copy, we need to import the copy module and then call the deepcopy() function within that module.
1import copy
2
3acc_schools = [["Duke", "UNC", "NCSU"], "Notre Dame", "Wake Forest"]
4deep_copy = copy.deepcopy(acc_schools)
5
6# now see what heppans to both lists if we delete an element from the "sublist"
7acc_schools[0].pop()
8print(acc_schools)
9print(deep_copy)
[['Duke', 'UNC'], 'Notre Dame', 'Wake Forest']
[['Duke', 'UNC', 'NCSU'], 'Notre Dame', 'Wake Forest']
View this execution on PythonTutor
Notice how this produces a new list for the Research Triangle universities.
13.8. Comparing#
Comparing two lists using boolean comparison operators (<,<=,==,>=,>) uses a lexicographical ordering. Initially, the interpreter compares the first items in each list. If they differ, then this difference is the outcome. Otherwise, the interpreter then compares the second items in each list. This comparison continues until the end of one list has reached. If all of the items in both lists are equal, then the lists are equal. Then if one list is shorter than the other after comparing elements up to that point, that list is considered smaller.
1a = ["one", "two"]
2b = ["one", "two"]
3c = ["one", "alpha", "two"]
4d = ["two", 3, "one"]
5e = ["one", "two", "three"]
6
7print("a < b:", a < b)
8print("a > b:", a > b)
9print("a == b:", a == b)
10print("c < a:", c < a)
11print("c > a:", c > a)
12print("a < d:", a < d)
13print("a > d:", a > d)
14print("b < c:", b < c)
15print("b < e:", b < e)
a < b: False
a > b: False
a == b: True
c < a: True
c > a: False
a < d: True
a > d: False
b < c: False
b < e: True
if statements can have a list as the conditional expression. A non-empty list resolves to True, and an empty list resolves to False.
1a = ["one", "two"]
2e = []
3if a:
4 print("a was not an empty list")
5else:
6 print("a was an empty list")
7
8if e:
9 print("e was not empty list")
10else:
11 print("e was an empty list")
a was not an empty list
e was an empty list
13.9. Converting#
We can directly convert a list to a boolean value with the built-in function bool():
1print(bool(a))
2print(bool(e))
True
False
To convert a list to a string, use the join() method from the string class.
1acc_schools = ["Duke", "Notre Dame", "UNC", "NCSU", "Wake Forest", "Clemson","Duke"]
2acc_string = ':'.join(acc_schools)
3print(acc_string)
Duke:Notre Dame:UNC:NCSU:Wake Forest:Clemson:Duke
What happens if you try to join a list that contains a mix of different types or a list that does not contain strings? Try below with mixed_list or primes
1# add code to join mixed_list or primes
13.10. Nested Lists#
In Python, we can nest lists - that is, create a list of lists. Nested lists are roughly comparable to creating multidimensional arrays in other programming languages. A common use case for nested lists is creating a matrix representing some specific abstraction.
For example, we could create a partially-completed tic-tac-toe board:
1board = [ ["X", " ", " "],
2 [" ", "O", " "],
3 [" ", "O", "X"]]
1rows = len(board) # the number of elements of top list equals the number of rows
2cols = len(board[0]) # the number of elements of a nested list equals the number of columns
3
4# print the board
5print("board: ")
6print(" ",board[0])
7print(" ",board[1])
8print(" ",board[2])
9
10# Accessing parts of the board
11print("Top right corner:", board[0][2])
12print("Top left corner:", board[0][0])
13print("bottom middle:", board[2][1])
board:
['X', ' ', ' ']
[' ', 'O', ' ']
[' ', 'O', 'X']
Top right corner:
Top left corner: X
bottom middle: O
While the above example shows a list of strings, realize that creating nested data structures can be done arbitrarily. For instance, we could represent a Sudoku board as a 9 by 9 matrix - one way to do this in Python is a list of list. (Other 3rd party libraries such as NumPy provide alternatives.) For each element, we can then decide what to place in that “slot”. For Sudoku, it could be a known number or even another list of possible numbers.

The Iteration notebook will demonstrate how to create this data structure.
View list of lists on PythonTutor.com
13.11. Suggested LLM Prompts#
Provide 10 use cases of Python lists for financially related tasks.
Explain how indexing and slicing work in Python lists. Provide examples demonstrating how to access individual elements by index and how to extract sublists using slicing notation. Make sure to include explanations on zero-based indexing and the inclusive-exclusive nature of slicing.
Discuss nested lists as a way to represent two-dimensional arrays in Python. Provide examples of creating and accessing elements in nested lists, as well as performing operations like matrix traversal and element manipulation. Include an example of creating an n by m matrix with iteration.
Explain possible dangers using list multiplication when creating nested lists.
Explore the concept of mutability in Python lists and its implications. Provide explanations on how modifying a list in place affects its identity versus creating a new list. Discuss the advantages and disadvantages onfmutable versus immutable data types and their usage.
13.12. Review Questions#
What is a list in Python, and how does it differ from arrays in other programming languages?
What is list slicing, and how is it performed in Python?
How do list access operations compare to those from strings?
What happens when you pass a list to the
append()method? To theextend()method?How do you insert an item at a specific index in a list?
Discuss the difference between the pop() and remove() methods in Python lists.
How do you sort a list in Python, and what is the default sorting order?
Compare the sort() method with the sorted() function in Python lists.
Explain deep vs shallow copying including possible tradeoffs.
What are the performance implications of removing an element from the middle of a list versus the end?
13.13. Drill#
In a terminal window, open a python interpreter shell (i.e., execute python3 or python). Then perform the following operations:
Create a list called grades:
grades = [87.6, 92.3, 84.5, 90.0, 86.0, 98.6]
How many elements are in the list?
Provide two ways of getting the first element in the list.
Provide two ways of getting the last element in the list
Remove the first element from the list and return the value.
Remove the last element from the list and return the value.
Concatenate this list to grades:
[76.4, 99.2, 88.8]Remove the third to the last element from the list.
Sort the list
13.14. Exercises#
Write a short program that reads in a sentence from a user. Then create a list of words (punctuation can be included as part of the words) by separating the words/characters by whitespace. Then reverse the list. Finally, combine the list into a single string with words separated by a colon and print the resulting string.
Write a function, ascending, that returns true if each of the elements in list is greater than the previous element.
Write a function, count_odds, that counts the number of odd numbers in a list.
Write a function, iterate_lists, that iterates through two lists at the same time, print the content of an element from the first list, followed by printing an element from the second list. If one list is longer than the others, then all of those elements should be printed.