Which Collections Keep Their Order
Concepts covered: Lists
Every collection you have met so far takes items one at a time. This section asks whether the collection remembers the sequence those items arrived in, because that decides whether a position like slot 0 means anything when you read the items back out.
Lists and tuples: position is the whole point
A list stores items in numbered slots starting at 0. The first value you append lands in slot 0, the next in slot 1, and nothing moves unless you remove something. A tuple works the same way, built once with its items already seated. Both answer steps[0] with the item that went in first, every time the program runs, on every computer.
steps = ["extract", "clean", "load"]
steps.append("report")
print(steps)
print(steps[0], steps[3])
duration = (3, 12, 48)
print(duration)
print(duration[2])Output:
['extract', 'clean', 'load', 'report'] extract report (3, 12, 48) 48
Appending report put it in slot 3, the next free position, and the earlier 3 items stayed where they were. The tuple answered slot 2 with 48 because that is where 48 sat when the tuple was written.
Dicts: keys come back in the order they went in
A dict stores pairs, and since Python 3.7 the language guarantees that the keys come back in the order they were first inserted. Reassigning a value to a key that already exists changes the value and leaves the key in its original position. Deleting a key and adding it again puts it at the end, because that counts as a fresh insertion.
stage_seconds = {}
stage_seconds["load"] = 20
stage_seconds["extract"] = 12
stage_seconds["clean"] = 5
print(stage_seconds)
stage_seconds["load"] = 25
print(stage_seconds)
del stage_seconds["load"]
stage_seconds["load"] = 25
print(stage_seconds)Output:
{'load': 20, 'extract': 12, 'clean': 5}
{'load': 25, 'extract': 12, 'clean': 5}
{'extract': 12, 'clean': 5, 'load': 25}Line 7 changed the value under load and the key stayed in front. Deleting it and adding it back moved it to the end, since the second add is a new insertion with no memory of the old one.
Sets: no slots, so no order
A set keeps no slots at all. It stores each item at a spot computed from the item's own value, which is what lets 30 in tags answer without scanning, and it means the order you added items plays no part in the order Python prints them. Small integers often come out in numeric order on the standard interpreter, so {3, 1, 2} prints as {1, 2, 3}, which looks like sorting but is a side effect of where those numbers land. Strings come out in an order that can change between one run and the next, so code that depends on set order can pass on one run and fail on the next.
arrivals = [30, 10, 20]
in_order = []
no_order = set()
for value in arrivals:
in_order.append(value)
no_order.add(value)
print("list:", in_order)
print("set:", no_order)
print("first in list:", in_order[0])
print("30 in set:", 30 in no_order)list: [30, 10, 20]
set: {10, 20, 30}
first in list: 30
30 in set: True
Step through it and watch in_order grow at the end while no_order places each value where its number sends it. The 2 collections hold the same 3 integers and answer different questions: the list knows what came first, the set knows what is present.
tags = {30, 10, 20}
print(30 in tags)
print(15 in tags)
print(len(tags))Output:
True False 3
Both membership checks answered at once, because answering them is what a set is built for. Add a line print(tags[0]) and the program stops there with TypeError: 'set' object is not subscriptable. There is no slot 0 to read, and the error names the operation the set refused: subscripting, the word Python uses for square brackets written after a value.
| Collection | Remembers insertion order | Reads by position |
|---|---|---|
| list | yes | yes |
| tuple | yes | yes |
| dict | yes, for keys | no, reads by key |
| set | no | no |
Practice
Predict each result before you pick, then read the explanations for the options you ruled out.
What does this program print?
queue = {}
queue["c"] = 3
queue["a"] = 1
queue["c"] = 30
queue["b"] = 2
print(queue)- {'c': 30, 'a': 1, 'b': 2}
- {'a': 1, 'b': 2, 'c': 30}
- {'a': 1, 'c': 30, 'b': 2}
- {'c': 3, 'a': 1, 'b': 2}
The drill below depends on how each collection starts and grows. An empty list is [] and grows with append, which puts the item in the next free slot. An empty set is set(), since {} builds an empty dict, and it grows with add, which files the item by its value. A set has no append and a list has no add, so pairing a collection with the other one's method stops the program with an AttributeError.
| Question | list | set |
|---|---|---|
| Empty one is written | `[]` | `set()` |
| Adds an item with | `append` | `add` |
| A repeated value | takes a new slot | is ignored |
| Reading slot 0 | returns the first item | raises TypeError |
About this lesson
This section is part of the Data Structures: Beginner lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.