MGU Computer Science Series — Programming with Python
Part IV: Data Structures
Lists · Indexes · Iteration · Search · Patterns
Chapter 17 of 30
17
MGU Computer Science Series  ·  Programming with Python  ·  Library Textbook Edition

Chapter 17:
Lists and Sequences

Storing, reading, changing, searching, and processing collections of values — the workhorse data structure of practical Python programming

■ Part IV of VII ■

■ 10 Sections  •  Chapter 17 of 30 ■

Builds on Chapters 1–16 — variables, control flow, functions, and strings

Chapter Purpose and Learning Objectives

Every program you have written so far has worked with one value at a time. A variable holds one number. A string holds one piece of text. But real problems almost never involve a single value. A class has thirty students. A quiz has twenty questions. A store has thousands of items. A weather station records a temperature every hour for a year.

When a problem involves a collection of values, you need a data structure — a way of organizing multiple pieces of information so your program can work with all of them together. Python's most important and versatile data structure is the list.

What This Chapter Teaches

This chapter teaches you how lists work, how to create them, how to read and change their contents, how to loop through them, how to search them, and how to apply the patterns — totals, counts, maximums, minimums — that appear constantly in real programs. Lists are not just a new syntax rule. They change what kinds of problems you can solve. By the end of this chapter you should be able to create lists, access individual elements, update values, add and remove items, iterate through a list with a loop, search for values, slice a list, use common list methods, and write list-processing functions. You will also build a small to-do list manager as the chapter mini-project.

10Sections
12Objectives
17Key Terms
30Total Chapters

Learning Objectives

By the end of this chapter, you should be able to:

  1. 1Explain why lists matter and what problems they solve compared to separate variables.
  2. 2Create lists, including empty lists, and describe what kinds of values a list can hold.
  3. 3Use zero-based and negative indexes to access list elements, and explain the len() function.
  4. 4Read and update individual list elements, and explain why lists are mutable.
  5. 5Add elements with append() and insert(), and remove elements with remove() and pop().
  6. 6Iterate through a list with a for loop, including index-based iteration for modifying elements.
  7. 7Test membership with in, and search lists using index() and count().
  8. 8Extract portions of a list using slice notation.
  9. 9Apply common list methods, including sort(), sorted(), reverse(), extend(), clear(), and copy().
  10. 10Apply the core list patterns: totals, averages, counting, maximum/minimum, and collecting matches.
  11. 11Identify and correct common list errors, including IndexError and the append-assignment mistake.
  12. 12Design and build a small interactive program that manages a list of tasks.

Sections at a Glance

Sections 17.1 – 17.3
The Basics: Why Lists Exist, How to Create Them, How to Address Elements
Collections · List Literals · Indexes · Length

Why Lists Matter

Imagine you are writing a program that reads five test scores and computes their average. You already know how to do this with five separate variables:

score1 = 88
score2 = 74
score3 = 91
score4 = 65
score5 = 83

total = score1 + score2 + score3 + score4 + score5
average = total / 5
print(average)

This works. But what if there are fifty scores instead of five? You would need to write fifty variable names and then add them all by hand. And what if the number of scores is not known until the program runs — for example, because the user enters them one at a time? Separate variables cannot solve that problem at all.

A list solves both problems. Instead of five separate variables, you have one variable that holds all five scores together:

scores = [88, 74, 91, 65, 83]

You can loop over the list no matter how long it is. You can add new items to it while the program runs. You can pass the whole collection into a function with a single argument. You can sort it, search it, and measure it.

Lists appear everywhere in real Python programs:

  • A program that processes student names and grades
  • A program that stores the lines of a text file
  • A program that collects user inputs during a session
  • A program that tracks inventory items in a store
  • A program that simulates rolling a die many times and records every result

Once you understand lists, you will find yourself reaching for them constantly. They are the workhorse of practical Python programming.

Creating Lists

A list is written as a sequence of values separated by commas and enclosed in square brackets.

scores = [88, 74, 91, 65, 83]
names = ["Alice", "Bob", "Carlos", "Diana"]
temperatures = [98.6, 99.1, 97.8, 100.2]
flags = [True, False, True, True]

Each value inside a list is called an element or item. The elements are stored in order, from left to right, and that order is preserved. Python does not rearrange your list unless you ask it to.

A list can contain any type of value: integers, floats, strings, Booleans, or even other lists. A list can also mix types, though it is usually cleaner to keep one type per list:

mixed = [42, "hello", 3.14, True]   # valid but unusual

You can create an empty list with a pair of empty brackets:

items = []

An empty list is useful when you plan to add elements to the list as the program runs.

You can also use a variable to build a list:

first = 10
second = 20
third = 30
numbers = [first, second, third]
print(numbers)    # [10, 20, 30]

Python evaluates each expression inside the brackets and uses the resulting values.

Reading Checkpoint

Before moving on, make sure you can answer these without looking back: What characters mark the beginning and end of a list? What is each value inside a list called? What does an empty list look like?

Indexes and Length

Every element in a list has a position called its index. Python numbers list positions starting at zero, not one. This is called zero-based indexing and it appears in every modern programming language.

colors = ["red", "green", "blue", "yellow"]
#           0       1        2       3

The element "red" is at index 0. The element "green" is at index 1. The element "blue" is at index 2. The element "yellow" is at index 3.

To access a single element, write the list name followed by the index in square brackets:

colors = ["red", "green", "blue", "yellow"]

print(colors[0])    # red
print(colors[1])    # green
print(colors[3])    # yellow

Negative indexes count from the end of the list. The index -1 refers to the last element, -2 to the second-to-last, and so on:

print(colors[-1])   # yellow
print(colors[-2])   # blue

Negative indexes are useful when you need the last element and you do not know how long the list is.

The len() function returns the number of elements in a list:

colors = ["red", "green", "blue", "yellow"]
print(len(colors))    # 4

For a list with four elements, the valid indexes are 0, 1, 2, and 3. In general, the valid indexes for a list named items run from 0 to len(items) - 1. Trying to access an index outside this range produces an IndexError:

print(colors[4])    # IndexError: list index out of range
Common Error

This is one of the most common errors beginners make. Always remember that the last valid index is len(list_name) - 1, not len(list_name).

Worked Example 17.3.1
Using length and indexes
scores = [88, 74, 91, 65, 83]

print("Number of scores:", len(scores))
print("First score:", scores[0])
print("Last score:", scores[-1])
print("Second score:", scores[1])
Output
Number of scores: 5
First score: 88
Last score: 83
Second score: 74
Sections 17.4 – 17.6
Working With Contents: Changing Elements, Growing Lists, and Looping
Mutability · append() · remove() · for Loops

Reading and Updating List Elements

Once a list exists, you can read any element using its index, as shown in the previous section. You can also change a specific element by assigning a new value to its index position:

scores = [88, 74, 91, 65, 83]
print(scores[1])    # 74

scores[1] = 80
print(scores[1])    # 80
print(scores)       # [88, 80, 91, 65, 83]

The assignment scores[1] = 80 replaces the value at index 1 with the new value 80. The rest of the list is unchanged.

Lists in Python are mutable, which means their contents can be changed after they are created. This is different from strings, which you learned in Chapter 16 are immutable — once a string is created, you cannot change individual characters inside it.

Worked Example 17.4.1
Correcting a list

A program records five temperatures but the third reading was entered incorrectly. The temperature should be 98.9, not 98.0.

temps = [98.6, 99.1, 98.0, 100.2, 97.8]
print("Before correction:", temps)

temps[2] = 98.9
print("After correction:", temps)
Output
Before correction: [98.6, 99.1, 98.0, 100.2, 97.8]
After correction: [98.6, 99.1, 98.9, 100.2, 97.8]

You can also use a list element in an expression and then store the result back:

scores = [88, 74, 91, 65, 83]
scores[0] = scores[0] + 5    # add 5 bonus points to first score
print(scores[0])              # 93
Tracing Practice

Trace the following code and write down the value of numbers after each line, before reading the answer below.

numbers = [10, 20, 30, 40]
numbers[0] = 15
numbers[3] = numbers[3] - 10
numbers[1] = numbers[0] + numbers[2]
print(numbers)
After LineValue of numbers
Line 1[10, 20, 30, 40]
Line 2[15, 20, 30, 40]
Line 3[15, 20, 30, 30]
Line 4[15, 45, 30, 30]
Final Output
[15, 45, 30, 30]

Appending and Removing Items

Lists can grow and shrink while a program runs. The two most basic operations are adding an item to the end of a list and removing an item from a list.

Appending

The append() method adds a single element to the end of a list:

fruits = ["apple", "banana"]
fruits.append("cherry")
print(fruits)    # ['apple', 'banana', 'cherry']

fruits.append("date")
print(fruits)    # ['apple', 'banana', 'cherry', 'date']

append() always adds to the end. The list grows by one element each time you call it.

This is the standard way to build a list during a loop — you start with an empty list and append each new item as you go:

collected = []

collected.append(10)
collected.append(20)
collected.append(30)

print(collected)    # [10, 20, 30]

Removing by Value

The remove() method removes the first occurrence of a specific value:

fruits = ["apple", "banana", "cherry", "banana"]
fruits.remove("banana")
print(fruits)    # ['apple', 'cherry', 'banana']

Notice that only the first "banana" was removed. If you call remove() with a value that is not in the list, Python raises a ValueError:

fruits.remove("grape")    # ValueError: list.remove(x): x not in list

Removing by Index

The pop() method removes and returns the element at a given index. If you call it with no argument, it removes and returns the last element:

fruits = ["apple", "banana", "cherry"]
removed = fruits.pop()
print(removed)    # cherry
print(fruits)     # ['apple', 'banana']

removed = fruits.pop(0)
print(removed)    # apple
print(fruits)     # ['banana']

pop() is useful when you need to process items one at a time by removing them from the list.

Inserting

The insert() method adds an element at a specific position:

fruits = ["apple", "cherry"]
fruits.insert(1, "banana")
print(fruits)    # ['apple', 'banana', 'cherry']

insert(1, "banana") means: place "banana" at index 1, shifting everything else to the right.

Common Mistake — Appending Versus Assigning

A frequent error is accidentally replacing a list with None by misusing append().

# Incorrect
numbers = [1, 2, 3]
numbers = numbers.append(4)    # numbers is now None!
print(numbers)                 # None

append() modifies the list in place and returns None. The assignment numbers = numbers.append(4) stores None back into numbers. The correct approach is:

# Correct
numbers = [1, 2, 3]
numbers.append(4)
print(numbers)    # [1, 2, 3, 4]

Iterating Through Lists

The most important thing you can do with a list is loop through all of its elements. A for loop is designed exactly for this:

scores = [88, 74, 91, 65, 83]

for score in scores:
    print(score)
Output
88
74
91
65
83

The loop variable score takes on each element's value in order, from index 0 to the last index. The loop body runs once for each element.

You can do anything inside the loop body that you could do with a regular value:

scores = [88, 74, 91, 65, 83]

for score in scores:
    if score >= 90:
        print(score, "— Excellent")
    elif score >= 80:
        print(score, "— Good")
    else:
        print(score, "— Needs work")
Output
88 — Good
74 — Needs work
91 — Excellent
65 — Needs work
83 — Good

Iterating with an index. Sometimes you need both the element and its index. Use range(len(...)):

names = ["Alice", "Bob", "Carlos"]

for i in range(len(names)):
    print(i, names[i])
Output
0 Alice
1 Bob
2 Carlos

This is useful when you need to modify elements inside the loop (you must use the index to assign a new value) or when you need to compare adjacent elements.

Modifying elements during a loop. If you need to change every element, use index-based iteration:

scores = [88, 74, 91, 65, 83]

# Add 5 bonus points to every score
for i in range(len(scores)):
    scores[i] = scores[i] + 5

print(scores)    # [93, 79, 96, 70, 88]
Important Warning

Do not use for item in list and then try to change item to change the list. This does not work.

scores = [88, 74, 91, 65, 83]

for score in scores:
    score = score + 5    # changes the loop variable, not the list

print(scores)    # [88, 74, 91, 65, 83]  — unchanged!

The variable score is a copy of the element's value. Changing score does not change the list. To change the list, you must assign back using the index.

Sections 17.7 – 17.10
Searching, Slicing, Methods, and the Patterns That Tie It All Together
Membership · Slices · Built-in Methods · Accumulator Patterns

Membership and Searching

Checking Membership with in

The in operator tests whether a value exists anywhere in a list:

fruits = ["apple", "banana", "cherry"]

print("banana" in fruits)    # True
print("grape" in fruits)     # False

Use not in to test the opposite:

print("grape" not in fruits)    # True

in is commonly used inside if statements:

allowed = ["Alice", "Bob", "Carlos"]
name = input("Enter your name: ")

if name in allowed:
    print("Welcome,", name)
else:
    print("Access denied.")

Finding the Position of an Element

The index() method returns the index of the first occurrence of a value:

fruits = ["apple", "banana", "cherry", "banana"]
print(fruits.index("banana"))    # 1
print(fruits.index("cherry"))    # 2

If the value is not in the list, index() raises a ValueError. To search safely, check with in first:

if "grape" in fruits:
    print(fruits.index("grape"))
else:
    print("Not found")

Counting Occurrences

The count() method returns the number of times a value appears:

votes = ["yes", "no", "yes", "yes", "no", "yes"]
print(votes.count("yes"))    # 4
print(votes.count("no"))     # 2

Searching with a Loop

When you need more control over the search — for example, finding the first element that satisfies a condition — use a loop:

scores = [74, 88, 55, 91, 66, 83]

for i in range(len(scores)):
    if scores[i] >= 90:
        print("First score at or above 90:", scores[i], "at index", i)
        break
Output
First score at or above 90: 91 at index 3

The break statement exits the loop as soon as the first matching element is found.

Slicing Lists

A slice extracts a portion of a list and returns it as a new list. Slicing uses the same notation you learned for strings in Chapter 16.

scores = [88, 74, 91, 65, 83, 79, 95]
#           0   1   2   3   4   5   6

The slice syntax is list[start:stop], where start is the index to begin at (included) and stop is the index to stop before (not included):

print(scores[1:4])    # [74, 91, 65]
print(scores[0:3])    # [88, 74, 91]
print(scores[4:7])    # [83, 79, 95]

If you omit start, Python starts from the beginning:

print(scores[:3])    # [88, 74, 91]

If you omit stop, Python goes to the end:

print(scores[4:])    # [83, 79, 95]

A full slice scores[:] copies the entire list:

copy = scores[:]

This is useful when you need to work with a copy of a list without changing the original.

You can also use a third argument as the step:

print(scores[::2])    # [88, 91, 83, 95]  — every other element
print(scores[::-1])   # [95, 79, 83, 65, 91, 74, 88]  — reversed
Important

Slicing always produces a new list. The original list is not changed.

scores = [88, 74, 91, 65, 83]
first_three = scores[:3]
print(first_three)    # [88, 74, 91]
print(scores)         # [88, 74, 91, 65, 83]  — unchanged
Predict the Output
What does each line print?
numbers = [10, 20, 30, 40, 50, 60]
print(numbers[2:5])
print(numbers[:4])
print(numbers[3:])
print(numbers[::3])
Check Your Answers
[30, 40, 50]
[10, 20, 30, 40]
[40, 50, 60]
[10, 40]

Common List Methods

Python provides many built-in methods for working with lists. You have already seen append(), remove(), pop(), insert(), index(), and count(). Here are several more that appear frequently in real programs.

sort()

sort() rearranges the list in ascending order (smallest to largest for numbers, alphabetical for strings):

scores = [88, 74, 91, 65, 83]
scores.sort()
print(scores)    # [65, 74, 83, 88, 91]

names = ["Carlos", "Alice", "Diana", "Bob"]
names.sort()
print(names)    # ['Alice', 'Bob', 'Carlos', 'Diana']

To sort in descending order, pass reverse=True:

scores.sort(reverse=True)
print(scores)    # [91, 88, 83, 74, 65]

sort() modifies the list in place. It does not return a new list.

sorted()

sorted() is a built-in function (not a method) that returns a new sorted list without changing the original:

scores = [88, 74, 91, 65, 83]
ranked = sorted(scores)
print(ranked)    # [65, 74, 83, 88, 91]
print(scores)    # [88, 74, 91, 65, 83]  — unchanged

Use sort() when you want to rearrange the list itself. Use sorted() when you need a sorted copy and want to keep the original order.

reverse()

reverse() reverses the list in place:

items = [1, 2, 3, 4, 5]
items.reverse()
print(items)    # [5, 4, 3, 2, 1]

extend()

extend() adds all elements from another list to the end of the current list:

group_a = [88, 74, 91]
group_b = [65, 83, 79]
group_a.extend(group_b)
print(group_a)    # [88, 74, 91, 65, 83, 79]

This is different from append(), which would add the entire list as a single element:

group_a = [88, 74, 91]
group_b = [65, 83, 79]
group_a.append(group_b)
print(group_a)    # [88, 74, 91, [65, 83, 79]]   — a list inside a list

clear()

clear() removes all elements from a list:

items = [1, 2, 3]
items.clear()
print(items)    # []

copy()

copy() returns a shallow copy of the list:

original = [10, 20, 30]
duplicate = original.copy()
duplicate.append(40)

print(original)     # [10, 20, 30]  — unchanged
print(duplicate)    # [10, 20, 30, 40]

Method Summary Table

MethodWhat It DoesReturns
append(x)Adds x to the endNone (modifies in place)
insert(i, x)Inserts x at index iNone
remove(x)Removes first occurrence of xNone
pop(i)Removes and returns element at index iThe removed element
index(x)Returns first index of xInteger
count(x)Counts occurrences of xInteger
sort()Sorts the list in placeNone
reverse()Reverses the list in placeNone
extend(other)Adds all elements of otherNone
clear()Removes all elementsNone
copy()Returns a shallow copyNew list
Pattern to Notice

Methods that modify the list in place generally return None. Methods that read from the list return a value. This is by design and helps you avoid the common mistake of storing the result of a modifying method.

List Patterns: Totals, Counts, Maximums, and Minimums

Several patterns appear again and again whenever you work with lists. These patterns are so common that Python has built-in functions for some of them. Knowing both the manual loop approach and the built-in function approach makes you a more flexible programmer.

Total

To add up all elements in a list, use an accumulator:

scores = [88, 74, 91, 65, 83]
total = 0
for score in scores:
    total = total + score
print(total)    # 401

Python's built-in sum() function does the same thing in one step:

total = sum(scores)
print(total)    # 401

Average

Divide the total by the count of elements:

scores = [88, 74, 91, 65, 83]
average = sum(scores) / len(scores)
print(average)    # 80.2

Always guard against dividing by zero if the list might be empty:

if len(scores) > 0:
    average = sum(scores) / len(scores)
else:
    average = 0

Count Matching Elements

To count elements that satisfy a condition, use a counter variable:

scores = [88, 74, 91, 65, 83]
passing = 0
for score in scores:
    if score >= 70:
        passing = passing + 1
print(passing)    # 4

Maximum and Minimum

To find the largest element, track the largest value seen so far:

scores = [88, 74, 91, 65, 83]
highest = scores[0]
for score in scores:
    if score > highest:
        highest = score
print(highest)    # 91

Python's built-in max() and min() functions are simpler when you just need the value:

print(max(scores))    # 91
print(min(scores))    # 65

But the loop approach is essential when you need to track more than just the value — for example, when you need to know the index of the maximum:

scores = [88, 74, 91, 65, 83]
highest = scores[0]
highest_index = 0

for i in range(len(scores)):
    if scores[i] > highest:
        highest = scores[i]
        highest_index = i

print("Highest score:", highest)
print("At position:", highest_index)
Output
Highest score: 91
At position: 2

Collecting Matching Elements Into a New List

A common pattern is to loop through a list and collect items that pass a test into a new list:

scores = [88, 74, 91, 65, 83]
passing_scores = []

for score in scores:
    if score >= 70:
        passing_scores.append(score)

print(passing_scores)    # [88, 74, 91, 83]

This pattern — start with an empty list, loop through the original, append items that qualify — appears constantly in real programs.

Worked Example 17.10.1
Building a complete summary function
def summarize(scores):
    """Print a statistical summary of a list of scores."""
    if len(scores) == 0:
        print("No scores to summarize.")
        return

    total = sum(scores)
    count = len(scores)
    average = total / count
    highest = max(scores)
    lowest = min(scores)

    passing = 0
    for score in scores:
        if score >= 70:
            passing = passing + 1

    print("Count:", count)
    print("Total:", total)
    print("Average:", round(average, 1))
    print("Highest:", highest)
    print("Lowest:", lowest)
    print("Passing (70+):", passing)


test_scores = [88, 74, 91, 65, 83, 72, 59, 95]
summarize(test_scores)
Output
Count: 8
Total: 627
Average: 78.4
Highest: 95
Lowest: 59
Passing (70+): 6

This function uses multiple list patterns together and wraps them in a reusable design.

Chapter Summary

Key Terms

list
An ordered, mutable collection of values enclosed in square brackets.
element
A single value stored inside a list.
index
The numeric position of an element in a list, starting at zero.
zero-based indexing
The convention of numbering positions starting at 0, not 1.
mutable
Can be changed after creation. Lists are mutable; strings are not.
negative index
An index counted from the end of a list. -1 is the last element.
IndexError
The error raised when you try to access an index that does not exist in a list.
append()
A list method that adds one element to the end of a list.
remove()
A list method that removes the first occurrence of a specified value.
pop()
A list method that removes and returns the element at a given index.
insert()
A list method that adds an element at a specified position.
iteration
Processing each element in a sequence one at a time.
membership
Whether a value exists in a collection, tested with in.
slice
A portion of a list extracted using [start:stop] notation.
accumulator
A variable that collects a running total or gathered result over a loop.
sort() / sorted()
sort() reorders a list in place; sorted() returns a new sorted list without changing the original.
sum() / max() / min()
Built-in functions returning the total, largest, or smallest element of a numeric list.
PracticeCode Reading

Read each code block carefully. Do not run the code yet. Answer the questions below each block.

Exercise CR-1

numbers = [5, 3, 8, 1, 9, 2]
print(numbers[0])
print(numbers[-1])
print(numbers[2])
print(len(numbers))
  1. What does numbers[0] evaluate to?
  2. What does numbers[-1] evaluate to?
  3. What does numbers[2] evaluate to?
  4. What does len(numbers) return?

Exercise CR-2

items = ["pen", "notebook", "eraser", "ruler"]
items[1] = "marker"
items.append("scissors")
print(items)
  1. What is stored at items[1] before the assignment?
  2. What is stored at items[1] after the assignment?
  3. What does items.append("scissors") do to the list?
  4. What does the final print display?

Exercise CR-3

values = [10, 20, 30, 40, 50]
result = values[1:4]
print(result)
print(values)
  1. What indexes does values[1:4] include?
  2. What is stored in result?
  3. Is values changed by the slice? Why or why not?

Exercise CR-4

grades = [78, 92, 65, 88, 71, 55, 90]
high = []

for grade in grades:
    if grade >= 80:
        high.append(grade)

print(high)
  1. What condition determines whether a grade is added to high?
  2. Which grades from grades will be added to high?
  3. What does the final print display?
PracticeCode Tracing

Trace the following programs step by step. Write down the value of each variable after each line executes.

Exercise CT-1

data = [4, 7, 2, 9, 5]

total = 0
for value in data:
    total = total + value

print(total)

Trace the value of total after each iteration of the loop.

Iterationvaluetotal after update
144
2711
3213
4922
5527

What does the final print display?

Exercise CT-2

words = ["cat", "dog", "fish", "bird"]

for i in range(len(words)):
    words[i] = words[i].upper()

print(words)

Trace the value of words[i] after each iteration. What does the final print display?

Exercise CT-3

numbers = [3, 1, 4, 1, 5, 9, 2, 6]
largest = numbers[0]

for n in numbers:
    if n > largest:
        largest = n

print(largest)

Trace the value of largest after each iteration. What does the final print display?

PracticePredict the Output

For each code block, predict exactly what will be printed before running the code.

Exercise PO-1

items = [10, 20, 30, 40, 50]
print(items[0] + items[-1])
print(items[2])
print(len(items))

Exercise PO-2

numbers = [5, 3, 8, 1]
numbers.append(7)
numbers.sort()
print(numbers)

Exercise PO-3

letters = ["a", "b", "c", "d", "e"]
print(letters[1:3])
print(letters[:2])
print(letters[3:])

Exercise PO-4

values = [10, 20, 30, 40, 50]
count = 0
for v in values:
    if v > 25:
        count = count + 1
print(count)

Exercise PO-5

fruits = ["apple", "banana", "cherry"]
fruits.remove("banana")
fruits.insert(0, "mango")
print(fruits)
print(len(fruits))
PracticeDebugging and Error Analysis

Each program below contains one or more errors. Identify the error, explain what is wrong, and write the corrected code.

Exercise DA-1

scores = [88, 74, 91, 65, 83]
print(scores[5])

What type of error occurs? What is the fix?

Exercise DA-2

numbers = [1, 2, 3, 4, 5]
numbers = numbers.append(6)
print(numbers)

What is wrong? What will print(numbers) display, and why? Write the corrected version.

Exercise DA-3

prices = [9.99, 4.49, 14.99, 2.99]
total = 0
for price in prices:
    price = price + total
print(total)

The programmer wants to compute the total of all prices, but the program prints 0. Explain why this is wrong and write the corrected version.

Exercise DA-4

items = ["pen", "notebook", "eraser"]
for i in range(len(items)):
    print(items[i + 1])

What error will this program produce? At what point during execution does it occur? Write a corrected version that prints every item.

Exercise DA-5

names = ["Alice", "Bob", "Carlos"]
if "Diana" in names:
    pos = names.index("Diana")
    print("Diana is at position", pos)

This program does not crash, but it does not print anything when Diana is not in the list. Is this a bug or correct behavior? Add an else clause to handle both cases.

PracticeShort Programming Tasks

These exercises ask you to write, complete, or modify a program. Keep your solutions clean and readable.

  1. SP-1 — Build a list from input. Write a program that asks the user to enter five numbers one at a time and stores them in a list. After all five numbers are entered, print the list, its length, its total, and its average.
  2. SP-2 — Find values above average. Write a program that starts with a list of quiz scores: scores = [72, 85, 91, 60, 78, 88, 95, 65, 70, 82]. Compute the average. Then print all scores that are above the average, one per line. Label the output clearly.
  3. SP-3 — Reverse without using reverse(). Write a function called reverse_list(items) that takes a list and returns a new list with the elements in reverse order. Do not use the reverse() method or [::-1] slicing. Use a loop. Test your function with several lists, including an empty list.
  4. SP-4 — Remove duplicates. Write a function called remove_duplicates(items) that takes a list and returns a new list with all duplicate values removed, keeping the first occurrence of each value and preserving the order of first appearances. Example: remove_duplicates([3, 1, 4, 1, 5, 9, 2, 6, 5]) should return [3, 1, 4, 5, 9, 2, 6].
  5. SP-5 — Second largest. Write a function called second_largest(numbers) that returns the second largest value in a list of numbers. Assume the list has at least two elements and that not all elements are identical. Do not use sort(). Use a loop to find the two largest values.
  6. SP-6 — Count words. Write a program that starts with a sentence stored as a string, splits it into a list of words, and counts how many words have more than four characters. Print the count.
Mini-ProjectTo-Do List Manager

This project brings together the main skills from this chapter — creating lists, appending, removing, searching, and iterating — into a small interactive program.

Description

Write a console-based to-do list manager. The program should let the user:

  • View all current tasks
  • Add a new task
  • Mark a task as done (remove it from the list)
  • Check if a specific task is on the list
  • Quit the program

Sample Session

=== To-Do List Manager ===
1. View tasks
2. Add task
3. Mark task done
4. Search for task
5. Quit
Choose an option: 1

Your tasks:
  (No tasks yet)

Choose an option: 2
Enter new task: Buy groceries
Task added.

Choose an option: 2
Enter new task: Finish homework
Task added.

Choose an option: 2
Enter new task: Call dentist
Task added.

Choose an option: 1

Your tasks:
  1. Buy groceries
  2. Finish homework
  3. Call dentist

Choose an option: 3
Enter task to mark done: Finish homework
"Finish homework" removed.

Choose an option: 1

Your tasks:
  1. Buy groceries
  2. Call dentist

Choose an option: 4
Enter task to search for: Buy groceries
"Buy groceries" is on your list.

Choose an option: 5
Goodbye!

Requirements

  • Store tasks in a list.
  • Display tasks numbered starting from 1 (not 0 — this is for the user's benefit).
  • When the user tries to mark a task done that is not on the list, display a clear message without crashing.
  • Use a while loop to keep the menu running until the user quits.
  • Organize your code using functions. Suggested functions: show_tasks(tasks) — prints all tasks; add_task(tasks, task) — appends the task; complete_task(tasks, task) — removes the task if found; search_task(tasks, task) — checks and reports whether the task is on the list.
Extension (Optional)

Let the user reorder a task (move it to a different position in the list). Track how many tasks have been completed during the session and display the count when the user quits. Let the user view tasks sorted alphabetically without changing the original order.

Mixed ReviewCumulative Practice

These problems require skills from earlier chapters alongside the list skills from this chapter. This is by design — good programmers keep earlier knowledge active.

Exercise MR-1 — Functions and Lists

Write a function called clamp_all(numbers, low, high) that takes a list of numbers and two limits. It should return a new list where every value below low is replaced with low and every value above high is replaced with high. Values already between low and high stay unchanged.

Example: clamp_all([5, -3, 12, 7, 0, 15], 0, 10) returns [5, 0, 10, 7, 0, 10].

Exercise MR-2 — Loops, Conditions, and Lists

Write a program that generates a list of the first twenty multiples of a number entered by the user (1× through 20×) and then prints only the even multiples.

Exercise MR-3 — Strings and Lists

Write a function called initials(names) that takes a list of full names (each as a single string, like "Alice Johnson") and returns a list of initials (like "A.J.").

Exercise MR-4 — Scope and Lists

The following function is supposed to return a list of all numbers from 1 to n that are divisible by 3. Find the bug and fix it.

def divisible_by_three(n):
    result = []
    for i in range(1, n + 1):
        if i % 3 == 0:
            result.append(i)
    print(result)

numbers = divisible_by_three(20)
print(numbers)

Exercise MR-5 — File Thinking

You have not yet learned about files, but think about this problem: if a program reads a text file where each line contains one student's name, what data structure would you use to store all the names? How would you count them? How would you sort them? Write a brief explanation, and then write the code you would use if the names were already in a list.

Preview — Chapter 18
Tuples, Sets, and Dictionaries

Chapter 17 gave you lists: ordered, mutable collections you can iterate, search, slice, and grow. Lists are the right structure when order matters and when you expect to add, remove, and update elements freely.

But Python has other built-in collection types designed for different situations. Chapter 18 introduces three more. Tuples are ordered collections like lists, but they cannot be changed after they are created — you will learn when fixed data is actually an advantage. Sets are unordered collections of unique values, useful when you need to eliminate duplicates or test membership very quickly. Dictionaries store key-value pairs, letting you look up information by a meaningful name instead of a position number, and are among the most powerful and widely used data structures in Python.

Understanding when to reach for a list, a tuple, a set, or a dictionary is one of the most practical skills a programmer can develop. Chapter 18 begins that process.