Week 5 Lecture: Lists
Week 5 Lecture: Introduction to Lists
1. What is a List?
- A list is a data structure that stores an ordered collection of items.
- They solve the problem of needing to store many related values (like all student scores in a class) without creating a separate variable for each one.
- Lists have two essential properties:
- Ordered: The position of each item is preserved. The first item you add stays in the first position unless you move it.
- Mutable: “Mutable” means “changeable.” You can add, remove, or change items in a list after it has been created.
Syntax
Lists are created using square brackets [], with items separated by commas.
# A list of integers
prime_numbers = [2, 3, 5, 7, 11, 13]
# A list of strings
class_roster = ["Alice", "Bob", "Charlie"]
# An empty list, ready to be filled later
upcoming_assignments = []
# A list can even hold mixed data types
student_profile = ["Alice", 21, 3.85, True]
Common Mistake: Using parentheses
()or curly braces{}will create a different type of data structure. Always use square brackets[]for lists.
Example: Creating Lists
Problem: We need to track a student’s recent quiz scores and the subjects they correspond to.
Code:
# Create a list of integer quiz scores
quiz_scores = [88, 92, 100, 75, 95]
# Create a list of string subjects
subjects = ["Math", "Physics", "Chemistry", "History", "English"]
# Print the lists to the console to see their contents
print("Quiz Scores:", quiz_scores)
print("Subjects:", subjects)
Output:
Quiz Scores: [88, 92, 100, 75, 95]
Subjects: ['Math', 'Physics', 'Chemistry', 'History', 'English']
2. Accessing Elements: Indexing
To get a single item out of a list, you use its position, called an index.
- The Golden Rule of Indexing: It’s Zero-Based!
- The first item in a list is at index
0. - The second item is at index
1. - The last item is at index
length - 1.
- The first item in a list is at index
- Negative Indexing: Python provides a convenient shortcut to access items from the end of the list.
-1refers to the last item.-2refers to the second-to-last item, and so on.
Syntax
You access an item by putting its index in square brackets after the list variable’s name.
list_variable[index]
Important Note: The
IndexErrorIf you try to access an index that doesn’t exist (e.g., asking for index5in a list with only 5 items), Python will stop and give you anIndexError: list index out of range. This is one of the most common errors for beginners!
Example: Lap Times
Problem: Given a list of a runner’s lap times, we need to extract specific laps and calculate the difference between them.
Code:
lap_times = [45.5, 44.9, 46.1, 44.8, 45.2]
# Retrieve the first lap time (at index 0)
first_lap = lap_times[0]
# Retrieve the last lap time using negative indexing
last_lap = lap_times[-1]
# Calculate the difference between the second (index 1) and fourth (index 3) laps
# Note: an item from a list can be used in calculations just like any other variable.
difference = lap_times[3] - lap_times[1]
print(f"First lap time: {first_lap}")
print(f"Last lap time: {last_lap}")
print(f"Difference between lap 4 and lap 2: {round(difference, 2)} seconds")
Output:
First lap time: 45.5
Last lap time: 45.2
Difference between lap 4 and lap 2: -0.1 seconds
3. Processing Every Item: Looping Through Lists
Traversal (or iteration) is the process of visiting every element in a list, one by one, to perform an action. This is the most common way we work with lists. Python’s for loop provides a very clean and readable way to do this.
The Accumulator Pattern
This is a fundamental programming pattern used to calculate a cumulative value from a list (like a sum, average, or count).
- Initialize a variable (the “accumulator”) to a starting value (e.g.,
0). - Loop through the list.
- Accumulate: In each iteration, update the accumulator with the current item’s value.
Syntax
for temporary_variable in list_name:
# This code block runs once for each item.
# The temporary_variable will hold the current item's value.
Example: Calculating Total Expenses
Problem: Given a list of monthly expenses, calculate the total amount spent.
Code:
expenses = [1200.50, 345.00, 85.75, 201.00, 450.25]
# 1. Initialize an accumulator variable to zero
total_expenses = 0.0
# 2. Use a for loop to traverse the list
for expense in expenses:
# 3. Add the current item's value to the accumulator
total_expenses += expense # This is a shortcut for total_expenses = total_expenses + expense
# After the loop finishes, the total is complete
print(f"Total monthly expenses: ${total_expenses:.2f}")
Output:
Total monthly expenses: $2282.50
4. Changing a List: Mutability and List Methods
Because lists are mutable, we can change their contents after they’ve been created. Python provides built-in functions that “belong” to lists, called methods, to help us do this. You call a method using a dot (.) after the list variable.
Common List Methods for Modification
| Method | Description |
|---|---|
list.append(item) |
Adds an item to the very end of the list. |
list.insert(index, item) |
Inserts an item at a specific index, shifting other items over. |
list.remove(value) |
Removes the first occurrence of a value. (Causes an error if not found). |
list.pop(index) |
Removes the item at a given index and returns its value. If index is omitted, it removes the last item. |
list[index] = new_value |
Replaces the item at an existing index with a new value. |
Example: Managing a Party Guest List
Problem: We need to manage a dynamic guest list where people are added and removed.
Code:
# Start with an initial guest list
guests = ["Alice", "Bob", "Charlie"]
print(f"Initial guests: {guests}")
# A new guest, "David", confirms. Add him to the end.
guests.append("David")
print(f"After adding David: {guests}")
# A VIP guest, "Eve", needs to be at the start of the list (index 0).
guests.insert(0, "Eve")
print(f"After adding VIP Eve: {guests}")
# "Bob" cancels. Remove him by his name.
guests.remove("Bob")
print(f"After Bob cancels: {guests}")
# The last person to arrive has to leave.
guests.pop() # .pop() with no argument removes the last item
print(f"After the last person leaves: {guests}")
# We misspelled "Alice". Let's correct it by changing the value at index 1.
guests[1] = "Alicia" # The first guest 'Eve' is at index 0
print(f"After correcting a name: {guests}")
Output:
Initial guests: ['Alice', 'Bob', 'Charlie']
After adding David: ['Alice', 'Bob', 'Charlie', 'David']
After adding VIP Eve: ['Eve', 'Alice', 'Bob', 'Charlie', 'David']
After Bob cancels: ['Eve', 'Alice', 'Charlie', 'David']
After the last person leaves: ['Eve', 'Alice', 'Charlie']
After correcting a name: ['Eve', 'Alicia', 'Charlie']
5. Getting Portions of a List: Slicing
Slicing lets you create a new list that is a subset or “slice” of an original list.
- Crucial Point: Slicing does not modify the original list. It always creates a new, smaller list.
Syntax: [start:stop:step]
start: The index where the slice begins (inclusive). If omitted, it defaults to the beginning (0).stop: The index where the slice ends (exclusive). This is the most important part! The slice goes up to but does not include this index. If omitted, it defaults to the very end.step: How many items to “jump” over. Defaults to1.
Remember:
my_list[0:3]gets the items at indices0,1, and2, but not3.
Common Slicing Shortcuts
my_list[:4]- Get all items from the beginning up to index 4 (exclusive).my_list[2:]- Get all items from index 2 (inclusive) to the very end.my_list[:]- Create a complete copy of the list.my_list[::-1]- A clever trick to create a reversed copy of the list.
Example: Marathon Water Stations
Problem: From a list of all water stations in a marathon, create separate lists for the early stations, the late stations, and stations for runners who only want water every 10km.
Code:
water_stations = [5, 10, 15, 20, 25, 30, 35, 40]
print(f"Original stations: {water_stations}")
# 1. Get the first three stations (indices 0, 1, 2)
early_stations = water_stations[0:3]
print(f"Early stations: {early_stations}")
# 2. Get stations from 25km (index 4) to the end
late_stations = water_stations[4:]
print(f"Late stations: {late_stations}")
# 3. Get every other station using a step of 2
every_other_station = water_stations[::2]
print(f"Every other station: {every_other_station}")
# 4. Prove the original list was not changed by slicing
print(f"Original stations (unchanged): {water_stations}")
Output:
Original stations: [5, 10, 15, 20, 25, 30, 35, 40]
Early stations: [5, 10, 15]
Late stations: [25, 30, 35, 40]
Every other station: [5, 15, 25, 35]
Original stations (unchanged): [5, 10, 15, 20, 25, 30, 35, 40]
Practice Problems
These problems are designed to help you practice the concepts we learned about lists. They will require you to combine your knowledge of lists with concepts from previous weeks, such as functions, if/else statements, and loops.
Try to solve each problem on your own before looking at the solutions at the end of this page. The best way to learn is by trying, making mistakes, and debugging your own code!
Problem 1: Filtering High Scores
Problem Statement:
Write a Python function called filter_high_scores that takes two arguments:
- A list of integers named
scores. - An integer named
threshold.
The function should iterate through the scores list and create a new list containing only the scores that are greater than or equal to the threshold. The original scores list should not be modified. Finally, the function should return the new list of high scores.
Examples:
- Calling
filter_high_scores([88, 91, 75, 99, 82], 90)should return the list[91, 99]. - Calling
filter_high_scores([10, 25, 50, 75], 50)should return the list[50, 75]. - Calling
filter_high_scores([60, 70, 80], 90)should return an empty list[].
Problem 2: Applying a Grade Curve
Problem Statement:
Write a Python function named curve_grades that modifies a list of student grades in-place (meaning you change the original list directly). The function should accept two arguments:
- A list of numbers (integers or floats) named
grades. - A number named
curve_pointsrepresenting the points to add to each grade.
Your function should iterate through the grades list and add curve_points to each grade. However, there is a maximum possible grade of 100. If adding the curve points would result in a grade over 100, the grade should be set to 100 exactly.
Since you are modifying the list in-place, your function should not return any value.
Example Behavior:
- You start with a list
test_scores = [85, 92, 77, 68, 100]. -
After you call
curve_grades(test_scores, 5), thetest_scoreslist itself should now be[90, 97, 82, 73, 100]. - You start with a list
final_exams = [95, 88, 98]. - After you call
curve_grades(final_exams, 7), thefinal_examslist should now be[100, 95, 100].
Problem 3: Reversing a List In-Place
Problem Statement:
While you can easily reverse a list with the slice [::-1], understanding how to do it manually is a classic and important programming exercise.
Write a function called reverse_list_in_place that takes one argument: a list named data_list.
The function should reverse the elements of data_list in-place, meaning you should modify the original list directly without creating a new one. Because of this, the function should not return any value.
Hint: Use two index variables, one starting at the beginning of the list (left) and one at the end (right). In a loop, swap the elements at the two index positions, and then move the indices towards the center of the list (left moves forward, right moves backward). The loop should stop when the indices meet or cross each other.
Example Behavior:
- You start with
letters = ['a', 'b', 'c', 'd', 'e']. -
After calling
reverse_list_in_place(letters), theletterslist should be['e', 'd', 'c', 'b', 'a']. - You start with
numbers = [1, 2, 3, 4]. - After calling
reverse_list_in_place(numbers), thenumberslist should be[4, 3, 2, 1].
Solutions
Reminder: Please attempt the problems on your own before reviewing these solutions!
Solution for Problem 1: Filtering High Scores
def filter_high_scores(scores, threshold):
"""
Creates a new list containing scores greater than or equal to a threshold.
"""
# Create an empty list to store the results
high_scores = []
# Traverse the input list of scores
for score in scores:
# Check if the current score meets the condition
if score >= threshold:
# If it does, add it to our new list
high_scores.append(score)
return high_scores
# --- Testing the function ---
scores1 = [88, 91, 75, 99, 82]
threshold1 = 90
print(f"Scores above {threshold1}: {filter_high_scores(scores1, threshold1)}")
scores2 = [10, 25, 50, 75]
threshold2 = 50
print(f"Scores above {threshold2}: {filter_high_scores(scores2, threshold2)}")
Solution for Problem 2: Applying a Grade Curve
def curve_grades(grades, curve_points):
"""
Modifies a list of grades in-place by adding a curve, capped at 100.
"""
# We need the index to modify the list, so we use range(len()).
for i in range(len(grades)):
new_score = grades[i] + curve_points
if new_score > 100:
grades[i] = 100
else:
grades[i] = new_score
# This function does not have a return statement.
# --- Testing the function ---
test_scores = [85, 92, 77, 68, 100]
print(f"Original scores: {test_scores}")
curve_grades(test_scores, 5) # Modify the list in-place
print(f"Curved scores: {test_scores}")
final_exams = [95, 88, 98]
print(f"Original exams: {final_exams}")
curve_grades(final_exams, 7)
print(f"Curved exams: {final_exams}")
Solution for Problem 3: Reversing a List In-Place
def reverse_list_in_place(data_list):
"""
Reverses a list's elements in-place using the two-pointer technique.
"""
# 'left' pointer starts at the first element (index 0)
left_index = 0
# 'right' pointer starts at the last element
right_index = len(data_list) - 1
# Loop until the pointers meet or cross in the middle
while left_index < right_index:
# Swap the elements at the left and right pointers
# A common way to swap two variables in Python
data_list[left_index], data_list[right_index] = data_list[right_index], data_list[left_index]
# Move the pointers closer to the center
left_index += 1
right_index -= 1
# --- Testing the function ---
letters = ['a', 'b', 'c', 'd', 'e']
print(f"Original letters: {letters}")
reverse_list_in_place(letters)
print(f"Reversed letters: {letters}")
numbers = [1, 2, 3, 4]
print(f"Original numbers: {numbers}")
reverse_list_in_place(numbers)
print(f"Reversed numbers: {numbers}")
This content will be available starting October 28, 2025.