Skip to content

Collections

  • Lesson 5
  • 40 min
  • Module 2: Values and control flow
Lesson 5 of 18 · Python for Practical AI EngineeringCollections

What you will be able to do

Keep a set of support tickets in one variable, with a record for each ticket, and go through them one by one. Every program that processes data, from this course’s ticket-cleaner to a model’s training data, starts with this structure.

NotebookDo this lesson in a notebookColab · Kaggle · GitHub

The notebook has every example, task and check of this lesson, with the instructions. It needs no install and no local project: only Python. Read the explanations here, and run the code there.

Colab and Kaggle open your own copy. They need a free Google or Kaggle account. Stuck? See the solution notebook.

Before you startWhat to know and to have readyAbout 40 minutes

What you need to know

What you need on your computer (only for the local route; the notebook and the boxes on this page need none of it)

Tested with Python 3.14 (terminal) and Pyodide 314.0 (browser). The notebook was tested in Jupyter.

A collection is one value that holds other values. Python has four main kinds. Each one fits a different job:

Kind Example Use it when
list ["open", "closed", "open"] The order matters, and items can repeat. You can add and remove items.
tuple ("T-1001", "open") A small, fixed group of values that belong together. It cannot change.
set {"billing", "login"} You need each value only once, and the order does not matter.
dictionary {"id": "T-1001", "status": "open"} You look up a value by a name (a key).

Most of the work in this course uses two of them together: a list of dictionaries. Each dictionary is one ticket, and the list holds all the tickets.

A list is a sequence of values in square brackets. Each item has a position, called its index. The index starts at 0, not 1:

statuses = ["open", "closed", "open", "pending"]
Code Result Meaning
statuses[0] "open" The first item.
statuses[1] "closed" The second item.
statuses[-1] "pending" The last item. Negative indexes count from the end.
len(statuses) 4 The number of items. The last index is always len - 1.
statuses[1:3] ["closed", "open"] A slice: from index 1 up to, but not including, index 3.
statuses.append("open") (changes the list) Adds an item at the end. Now len(statuses) is 5.

Why does the index start at 0? The index counts how many items come before the item. The first item has zero items before it.

To do something with each item, use a for loop:

for status in statuses:
print(status)

Python gives the name status to the first item and runs the indented line. Then it gives status the next item, and runs the line again, until there are no more items. The line after for must be indented (four spaces), and the for line ends with :. The indent shows which lines are inside the loop. You learn more about loops in the next lesson.

A list finds a value by its position. A dictionary finds a value by a key: a name that you choose. Each entry is a key and a value, with : between them:

ticket = {"id": "T-1001", "status": "open", "category": "billing", "priority": 2}
Code Result Meaning
ticket["category"] "billing" The value for the key "category".
ticket["assignee"] error: KeyError: 'assignee' The key does not exist.
ticket.get("assignee") None Like [ ], but gives None when the key does not exist.
ticket.get("assignee", "nobody") "nobody" Gives your default value when the key does not exist.
ticket["status"] = "closed" (changes the dictionary) Changes a value, or adds the key if it is new.

A dictionary is a good fit for a record: the keys are the field names, so ticket["priority"] explains itself. With a list, ticket[3] does not.

To go through every key and value, loop over .items(). Each step gives you two values, a key and its value:

for key, value in ticket.items():
print(key, "=", value)
Output
id = T-1001
status = open
category = billing
priority = 2

A tuple is like a list, in round brackets, but it cannot change after you make it. Use it for a small group of values that belong together, such as a pair. You can unpack a tuple into separate names in one line:

pair = ("T-1001", "open")
ticket_id, status = pair # ticket_id is "T-1001", status is "open"

A set keeps each value only once. Make one from a list to find the different values in it, and use in to check if a value is there:

categories = set(["billing", "login", "billing", "shipping"])
print(categories) # {'billing', 'login', 'shipping'}, in any order
print("login" in categories) # True

A set has no order, so it can print the items in a different order on your computer. Use sorted(categories) when you need a fixed order. in also works on lists, strings and dictionary keys.

Here are the six tickets that the rest of this module uses. Read the code from the outside in: a list ([ ]) with six dictionaries ({ }) in it.

Run Python in your browser

Explore the tickets

Before you press Run, predict the first three lines of the output. Then run it and compare.

tickets[-1]["category"] has two steps. tickets[-1] gives the last dictionary. ["category"] then gets one value from that dictionary. Read it from left to right.

Guided practice: answer questions about the tickets

Section titled “Guided practice: answer questions about the tickets”

Use the same six tickets. Each step asks for one value. Write the code in the box, under the list.

  1. Show the status of the third ticket (T-1003). Expected output: open.
  2. Make a set of all the categories, then show it sorted. Expected: ['billing', 'login', 'shipping'].
  3. Check if any ticket has the category "refund". Expected: False.
  4. Change the status of the first ticket to "closed", then show the whole first ticket.

Run Python in your browser

Guided practice

Steps 1 and 2 are done for you. set() makes an empty set, and .add() puts one value in it. Do steps 3 and 4 yourself.

Show the answers for steps 3 and 4
# 3. Is there a "refund" ticket?
print("refund" in categories)
# 4. Close the first ticket, then show it.
tickets[0]["status"] = "closed"
print(tickets[0])

This part explains one of the most common surprises in Python. = does not copy a value. It gives the value another name. Look at this code:

tickets = ["T-1001", "T-1002"]
backup = tickets
tickets.append("T-1003")
print(backup)

Most people expect backup to have two items. It has three. Here is the state after each line:

After line tickets refers to backup refers to The list itself
1 list A (not yet) A: ["T-1001", "T-1002"]
2 list A list A A: ["T-1001", "T-1002"]
3 list A list A A: ["T-1001", "T-1002", "T-1003"]

There is only one list. backup = tickets made a second name for it, so a change through one name is visible through the other. The same is true for dictionaries and sets. It is not a problem for numbers and strings, because they cannot change: hours = hours + 2 makes a new number.

To make a real copy, call .copy(): backup = tickets.copy(). Now backup is a new list with the same items, and append changes only one of them.

Run Python in your browser

Predict, then run

Write down the three numbers that you expect. Then press Run.

You have the six tickets in a list. A colleague asks for tickets by ID, many times a day. Make a dictionary by_id whose keys are the ticket IDs and whose values are the ticket records. Then by_id["T-1004"]["status"] must give "pending".

Run Python in your browser

Your turn: build by_id

Start with an empty dictionary, and add one entry for each ticket with a loop.

Show one answer
by_id = {}
for ticket in tickets:
by_id[ticket["id"]] = ticket

Each step of the loop adds one key (the ticket’s ID) with the whole record as its value. A lookup by key is fast, even with a million tickets, because a dictionary does not search through the items one by one.

Common mistake

IndexError and KeyError

Symptom: the program stops with one of these errors:

IndexError: list index out of range
KeyError: 'assignee'

Cause: you asked for an item that is not there. IndexError means that the position is too large: a list with 6 items has the indexes 0 to 5, so tickets[6] does not exist. KeyError means that the dictionary has no such key. The key in the message shows what Python looked for. Check the spelling and the capital letters: "Status" and "status" are different keys.

Fix:

  1. Print what is there: print(len(tickets)) for a list, print(ticket.keys()) for a dictionary.
  2. For a list, use an index below len(...), or -1 for the last item.
  3. For a dictionary key that can be missing, use .get("key"), and decide what to do when the result is None.

Check your understanding

Predict the output: statuses = ["open", "closed"]; same = statuses; same.append("pending"); print(len(statuses))

Show the answer

3. same = statuses does not copy the list. Both names refer to one list, so append through same changes the list that statuses refers to. Use statuses.copy() when you need a separate list.

Check your understanding

Which collection fits each job? (a) The six tickets in the order they arrived. (b) The different categories that appear. (c) One ticket's fields. (d) A ticket ID and its new status, passed together.

Show the answer

(a) A list: the order matters. (b) A set: each category only once. (c) A dictionary: you look up fields by name. (d) A tuple: two values that belong together and do not change.

Recap

  • A list keeps items in order. The index starts at 0, and -1 is the last item.
  • A dictionary finds a value by its key. Use .get() when a key can be missing.
  • A tuple is a fixed group of values. A set keeps each value once, with no order.
  • for item in collection: runs the indented lines once for each item.
  • = gives a value another name. It does not copy. Use .copy() for a separate list or dictionary.

Next, you make decisions with if, and use loops to filter the tickets and count them by category.

Next: Decisions and repetition