list: Creating, Accessing, Adding, Removing, Searching and Looping

Lesson goals
  • Create a list and access items by positive and negative index
  • Add and remove items with append, insert, remove, pop and del
  • Search a list with in, index and count
  • Loop over a list, including with enumerate, and sort it

What will we learn?

list is the most common data structure in Python. We already used it briefly. Today we will learn it properly:

  • Creating it and accessing items.
  • Adding, removing and changing.
  • Searching.
  • Looping and sorting.

Why do we need this?

Almost every program holds collections: a list of students, products in a cart, today’s orders, lines from a file, results of a Database query (the backend and databases topics). When the number is not known in advance, you cannot keep a separate variable for each item (student1, student2…). A list holds as many as needed, in a certain order.

Explanation from the basics

What is a list?

A list is an ordered collection of values:

  • Ordered — every item has a fixed position, the index.
  • Mutable — you can add, remove and change items after it is created.
  • Allows duplicates — the same value can appear several times.
  • Any type — you can mix them ([1, "a", True]), but usually a list holds items of the same kind.
Analogy: a train

A list is a train with numbered cars. Every car (item) carries a load (a value). The first car is number 0, not 1. You can attach a car at the end (append), put a car in the middle (insert), or detach a car (remove/pop).

Indexes

fruits = ["apple", "banana", "cherry", "date"]
index:       0         1         2        3
negative:   -4        -3        -2       -1
  • Counting starts from 0.
  • A negative index counts from the end: -1 = the last one, -2 = the one before last.
  • An index that does not exist → IndexError.

Syntax

# create
empty = []
numbers = [10, 20, 30]

# access and change
numbers[0]          # 10 - first item
numbers[-1]         # 30 - last item
numbers[1] = 25     # change an item
len(numbers)        # 3 - how many items

# add
numbers.append(40)       # add to the end
numbers.insert(0, 5)     # insert at index 0, pushing the rest right

# remove
numbers.remove(25)       # remove the FIRST item equal to 25
last = numbers.pop()     # remove and return the last item
first = numbers.pop(0)   # remove and return the item at index 0
del numbers[0]           # delete by index (returns nothing)
numbers.clear()          # remove everything

# search
30 in numbers            # True / False
numbers.index(30)        # index of the first 30 (ValueError if missing)
numbers.count(30)        # how many times 30 appears

# sort
numbers.sort()               # sorts THIS list in place
numbers.sort(reverse=True)   # descending
sorted(numbers)              # returns a NEW sorted list, original unchanged

A method is a function that “belongs” to an object, and is called with a dot: numbers.append(40). We will learn about methods in depth in the OOP topic. For now: “an action the list knows how to do on itself”.

First code example

week-2/shopping_list.py:

shopping = ["milk", "bread", "eggs"]
print("Start:", shopping)

shopping.append("cheese")
print("After append:", shopping)

shopping.insert(1, "butter")
print("After insert:", shopping)

shopping.remove("bread")
print("After remove:", shopping)

print("First item:", shopping[0])
print("Last item:", shopping[-1])
print("Items count:", len(shopping))

Output:

Start: ['milk', 'bread', 'eggs']
After append: ['milk', 'bread', 'eggs', 'cheese']
After insert: ['milk', 'butter', 'bread', 'eggs', 'cheese']
After remove: ['milk', 'butter', 'eggs', 'cheese']
First item: milk
Last item: cheese
Items count: 4

Breaking down the code line by line

LineWhat happened to the list
shopping = [...]Created with 3 items: indexes 0, 1, 2.
.append("cheese")Added at the end. Now 4 items.
.insert(1, "butter")Went in at index 1. What was there (bread) and what came after it moved right.
.remove("bread")Removed by value: Python looks for the first occurrence of "bread" and removes it.
shopping[0]The first item.
shopping[-1]The last item, without knowing how many there are.
len(shopping)The number of items.

Notice: append, insert and remove change the list itself and do not return a new list. That is why you do not write shopping = shopping.append(...) (more on that in the mistakes section).

Another example

Managing a checkout queue: looping, searching, pop and enumerate. week-2/queue.py:

queue = ["dana", "avi", "noa", "avi", "yossi"]

print("People in queue:", len(queue))
print("Is noa waiting?", "noa" in queue)
print("noa's position:", queue.index("noa") + 1)
print("How many times avi:", queue.count("avi"))

served = queue.pop(0)
print("Now serving:", served)

print("--- Remaining queue ---")
for position, name in enumerate(queue, start=1):
    print(position, name)

queue.sort()
print("Alphabetical:", queue)

Output:

People in queue: 5
Is noa waiting? True
noa's position: 3
How many times avi: 2
Now serving: dana
--- Remaining queue ---
1 avi
2 noa
3 avi
4 yossi
Alphabetical: ['avi', 'avi', 'noa', 'yossi']

Breakdown:

  • "noa" in queue — in goes over the list and checks whether the value exists. It returns a bool.
  • queue.index("noa") + 1 — index returns the index (2). We add 1 because for people, “third place” starts from 1.
  • queue.pop(0) — takes out and returns the first one. That is the difference from remove: pop gives you the value that was taken out, so we can use it (served).
  • enumerate(queue, start=1) — in every round it gives a pair: a running number and the item. for position, name in ... unpacks the pair into two variables. Without start=1, counting starts from 0.
  • queue.sort() — sorts the list itself, alphabetically for text and in ascending order for numbers.

Common mistake

Mistake 1: assigning the result of a method that changes the list in place.

names = ["noa", "avi"]
names = names.append("dana")
print(names)
None

append changes the list and returns None. We assigned the None into names, and lost the list! The fix: names.append("dana") on its own. The same goes for sort(), insert(), remove().

Mistake 2: Off-by-one on the last index.

items = ["a", "b", "c"]
print(items[len(items)])
IndexError: list index out of range

len is 3, but the last index is 2. The last one = items[-1] or items[len(items) - 1].

Mistake 3: remove on a value that does not exist.

items.remove("z")
ValueError: list.remove(x): x not in list

Check first: if "z" in items: items.remove("z").

Mistake 4: removing from a list while looping over it.

numbers = [1, 2, 2, 3]
for n in numbers:
    if n == 2:
        numbers.remove(n)
print(numbers)
[1, 2, 3]

We expected [1, 3]. When you remove an item, all the items move left, and the loop “skips” the next item. The safe solution: build a new list with what you want to keep:

numbers = [1, 2, 2, 3]
kept = []
for n in numbers:
    if n != 2:
        kept.append(n)
print(kept)   # [1, 3]

Practice

The exercises use only what was taught in this lesson and the lessons before it. Try on your own first, and only then open the solution.

Exercise 1: Indexes

days = ["Sun", "Mon", "Tue", "Wed", "Thu"]

Print, using indexes only: the first day, the last day (with a negative index), and the middle day.

Expected output:

Sun
Thu
Tue
Show solution
days = ["Sun", "Mon", "Tue", "Wed", "Thu"]

print(days[0])
print(days[-1])
print(days[2])
Sun
Thu
Tue

Indexes start from 0. A negative index counts from the end: -1 is the last item.

Exercise 2: A shopping list

Start from ["milk", "bread"], and do the following in order:

  1. Add "eggs" to the end.
  2. Add "butter" in the first place.
  3. Remove "bread".
  4. Print the list and the number of items.

Expected output:

['butter', 'milk', 'eggs']
3
Show solution
shopping = ["milk", "bread"]

shopping.append("eggs")
shopping.insert(0, "butter")
shopping.remove("bread")

print(shopping)
print(len(shopping))
['butter', 'milk', 'eggs']
3
  • append — to the end. insert(0, ...) — to a specific position.
  • remove — removes by value (the first occurrence).

Exercise 3: A queue

queue = ["dana", "avi", "noa", "avi", "yossi"]
  1. Check whether "noa" is in the queue, and print which place she is in (the first place is 1).
  2. Print how many times "avi" appears.
  3. Take out the first person in the queue and print Now serving: <name>, and the number of people who remain.

Expected output:

True
3
2
Now serving: dana
4
Show solution
queue = ["dana", "avi", "noa", "avi", "yossi"]

print("noa" in queue)
print(queue.index("noa") + 1)
print(queue.count("avi"))

served = queue.pop(0)
print("Now serving:", served)
print(len(queue))
True
3
2
Now serving: dana
4

pop(0) both removes and returns the item — that is why you can save it in a variable.

Exercise 4: Statistics on grades

grades = [78, 92, 55, 88, 100, 43, 67]

Print the highest grade, the lowest, the average (rounded to one digit), and a new list of the grades that passed (55 and above) — without changing grades.

Expected output:

Highest: 100
Lowest: 43
Average: 74.7
Passed: [78, 92, 55, 88, 100, 67]
Show solution
PASSING_GRADE = 55

grades = [78, 92, 55, 88, 100, 43, 67]

print("Highest:", max(grades))
print("Lowest:", min(grades))
print("Average:", round(sum(grades) / len(grades), 1))

passed = []
for grade in grades:
    if grade >= PASSING_GRADE:
        passed.append(grade)
print("Passed:", passed)
Highest: 100
Lowest: 43
Average: 74.7
Passed: [78, 92, 55, 88, 100, 67]

The pattern of “a new list + a loop + append” is the way to filter a list without touching the original.

Exercise 5: Removing during a loop

numbers = [1, 2, 2, 3, 2, 4]
for n in numbers:
    if n == 2:
        numbers.remove(n)
print(numbers)

The intention was to remove all the 2s, but one remained. Write a function remove_all(items, value) that returns a new list without any occurrence of value.

Expected output:

[1, 3, 4]
Show solution

When you remove from a list while looping over it, the items move left, and the loop skips the item that moved into the removed place. That is why you build a new list instead:

def remove_all(items, value):
    result = []
    for item in items:
        if item != value:
            result.append(item)
    return result


print(remove_all([1, 2, 2, 3, 2, 4], 2))
[1, 3, 4]

Summary

  • list = an ordered, mutable collection, with duplicates. Written with [ ].
  • An index starts at 0. -1 = the last one. An index that does not exist → IndexError.
  • Adding: append (to the end), insert (to a position). Removing: remove (by value), pop (by position, and it returns the item), del.
  • Searching: in, index, count. Looping: for, and enumerate when you also need a number.
  • Methods that change in place (append, sort…) return None. sorted() returns a new list.
  • Do not remove from a list while looping over it. Build a new list.

Official documentation