Advanced

Data Structures Deep Dive

Use sets, tuples, and advanced list techniques to model data efficiently.

What you will see

Ada CS CS

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Sets, tuples, and list tricks let you deduplicate, count, and model records in data. I compare a slow set-accumulation to a fast set, pull unique values with fromkeys, and check membership with both a list and a set, watching how each container answers uniqueness and lookup differently.

1

I deduplicate a list two ways: first a manual loop that accumulates unique values in a list, then a set. I print the length and contents of each to see the set produce the same answer in far less code.

nums = [1, 2, 2, 3, 3, 3] seen = [] for x in nums: if x not in seen: seen.append(x) print(len(seen)) print(len(set(nums)))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
3 3
A set drops duplicates but has no order, so the sequence of values can differ even when the count is the same.
2

Sets are built for membership, and their operators give set math for free. I find how many items two sets share and how many they cover together, printing each count to see intersection versus union.

a = {1, 2, 3} b = {2, 3, 4} print(len(a & b)) print(len(a | b))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
2 4
'&' is the intersection (items in both); '|' is the union (all items). Each is a set, so the result holds no duplicates.
3

Membership works the same both ways, but the list keeps duplicates and order while the set keeps only unique values. I run a lookup on each and print whether it is found, then print both containers to see what they actually hold.

nums = [1, 2, 2, 3, 3, 3] in_list = 2 in nums in_set = 2 in set(nums) print(in_list) print(in_set) print(set(nums))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
True True {1, 2, 3}
Both return True, but notice the set is unordered, {1, 2, 3} is not the same shape as the original list, which keeps repeats.
4

I pull unique values while keeping order using dict.fromkeys, which drops repeats but preserves first appearance. I print the result and confirm the order matches the input, not a sorted one.

nums = [3, 1, 2, 2, 1] print(list(dict.fromkeys(nums)))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
[3, 1, 2]
This is the trick to dedupe while keeping order, a plain set would shuffle them, and sorted() would reorder them.
5

Tuples store fixed records I can unpack directly into names. I split a student record into parts, read a field by index, and print each to see position versus name-based access side by side.

student = ("Ada", 21, "CS") name, age, major = student print(name) print(major) print(student[2])

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Ada CS CS
Unpacking needs the same number of variables as fields. Tuples also cannot change after creation, which is what makes them good records.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Containers store items; the right structure gives fast lookup or insertion depending on access pattern.
1 Pick container matching access pattern
↓
2 Store items -> hash (set/dict) or slot (list)
↓
3 Lookup by index or key -> O(1) or O(n)
↓
4 Set math combines two sets into a new set
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

nums = [1, 2, 2, 3, 3, 3] sets nothing on screen
seen = [] sets nothing on screen
for x in nums: sets nothing on screen
if x not in seen: sets nothing on screen
seen.append(x) sets nothing on screen
print(len(seen)) 3
print(len(set(nums))) 3
Why this works
Choosing the right structure

Match the container to the access pattern. Lists for ordered, mutable sequences. Tuples for immutable records. Sets for membership and uniqueness. Dicts for labelled lookup. Using the wrong one costs performance: e.g. 'x' in list is O(n) while 'x' in set is O(1) average.

Complexity at a glance
Operationlistdictset
Index/lookupO(n)O(1)*O(1)*
AppendO(1)*,,
MembershipO(n)O(1)*O(1)*

* is amortised average case. Prefer dict/set for frequent membership checks.

Examples

Using sets for uniqueness

Deduplicate with sets

nums = [1, 2, 2, 3, 3, 3]
unique = list(set(nums))      # [1,2,3]
a = {1, 2, 3}
b = {2, 3, 4}
print(a & b)   # {2, 3} intersection
print(a | b)   # {1,2,3,4} union

Sets are unordered and hold unique, hashable items, perfect for membership tests and math operations.

Tuples as records

Structured data

student = ("Ada", 21, "CS")
name, age, major = student   # unpacking
print(name, age, major)

Tuples group fixed fields. Use namedtuple for labelled tuples with attribute access.

Nested structures

Lists of dicts

students = [
    {"name": "Ada", "grade": 90},
    {"name": "Bob", "grade": 75},
]
highest = max(students, key=lambda s: s["grade"])
print(highest["name"])   # Ada

Combine containers: a list of dicts models rows. key= functions drive sorting and searching.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Error Handling
Previous Lesson
Error Handling
Next Lesson
Functional Programming
Functional Programming →