Choosing the Right Data Structure
Intermediate · 18 min read · ▶ live playground · ✦ checkpoint
The quiet beginner mistake is using a list for everything because lists feel familiar. A data structure is a way to organize values so certain jobs are easy, and Python gives you lists, tuples, dictionaries, and sets because those jobs are not the same.
Start with the question
A collection operation is one kind of action you do with a collection, such as looking up a value, adding a value, checking membership, or keeping order. The right collection depends on the operation you do most.
lineup = ["Mina", "Ravi", "Noor"]
player_record = ("Mina", 42, "focused")
served_lunch = {"Mina", "Noor"}
scores = {"Mina": 42, "Ravi": 35}
print(lineup[1])
print(player_record[0])
print("Noor" in served_lunch)
print(scores["Mina"])RaviMinaTrue42
Each line asks a different question:
- A list asks, "What is at this position?" It is still the row of numbered slots from lesson 5.1.
- A tuple asks, "What fixed record travels together?" It is still the sealed index card from lesson 5.2.
- A set asks, "Is this unique value present?" It is still the guest list at the door from lesson 6.2.
- A dictionary asks, "What value is under this label?" It is still the labeled cubbies from lesson 6.1.
That is the whole habit: name the question first, then choose the shape.
Mutable and immutable, side by side
Mutable means an object can change in place, and immutable means an object cannot change in place after it is created. This matters because a mutable collection can be edited through the same name tag. An immutable collection needs a new value when the data changes.
todo = ["pack lunch", "stretch"]
todo.append("read")
player_record = ("Mina", 42)
updated_record = ("Mina", 50)
checked_in = {"Mina", "Ravi"}
checked_in.add("Noor")
default_badges = frozenset(["helper", "fast finisher", "helper"])
scores = {"Mina": 42}
scores["Mina"] = 50
print(todo)
print(player_record)
print(updated_record)
print(sorted(checked_in))
print(sorted(default_badges))
print(scores)['pack lunch', 'stretch', 'read']('Mina', 42)('Mina', 50)['Mina', 'Noor', 'Ravi']['fast finisher', 'helper']{'Mina': 50}
The list, set, and dictionary changed in place. The tuple did not change; updated_record is a new tuple. The frozenset also stays fixed, while still keeping only one copy of "helper".
Choose mutable collections when the collection naturally changes over time: a task list, a scoreboard, a set of checked-in players. Choose immutable collections when the shape should feel stable: a coordinate, a fixed record, or a default set of badges.
Performance intuition without panic
Performance means how much work your program tends to do as data grows. You do not need stopwatch thinking yet. You need shape thinking.
vip_line = ["Mina", "Ravi", "Noor", "Ira"]
vip_set = set(vip_line)
snack_prices = {"apples": 2, "tea": 4, "mangoes": 5}
print("Noor" in vip_line)
print("Noor" in vip_set)
print(snack_prices.get("tea"))
print(snack_prices.get("rice", "not listed"))TrueTrue4not listed
Both membership checks return True, but they do not have the same shape. A list membership check may walk through items one by one until it finds a match. A set membership check is usually built for direct yes-or-no lookup. A dictionary key lookup is usually built for direct label-to-value lookup.
Lookup means finding a value you want. Insertion means adding a new value. Ordering means whether the collection has a meaningful sequence.
- Lists and tuples are strong when position and order matter.
- Sets are strong when uniqueness and membership matter.
- Dictionaries are strong when labels and values matter.
- Lists usually append cheaply at the end, but inserting near the front means other items shift.
- Tuples and frozensets do not insert in place; you build a new value instead.
A gentle taste of Big-O
Big-O notation is a shorthand for how the work tends to grow as the collection gets bigger. Think of it as a growth forecast, not a stopwatch.
Two beginner-friendly shapes matter here:
- O(1) means roughly constant work in the common case, so doubling the collection does not usually double that operation.
- O(n) means linear work, so the operation may grow with the number of items.
A list lookup by index, like players[0], is roughly O(1) because Python can go straight to that position. A list membership test, like "Noor" in players, is O(n) in the usual mental model because Python may need to check items one by one.
Set membership and dictionary key lookup are usually O(1) in everyday Python. That does not mean "magic" or "always fastest." It means their internal shape is designed so common lookups do not grow step by step with every item. You will study deeper trade-offs later; for now, this is enough to choose well.
Try it - choose shapes for one small program
Run the tracker, then change one collection at a time. Add a new shopping item, a new pantry item, and a new price. Notice how each structure has a different job.
Decision guide
Use this guide when you feel stuck:
- Use a list when order matters, duplicates are allowed, and the collection changes over time.
- Use a tuple when you have a small fixed record and changing it in place would be misleading.
- Use a set when uniqueness and membership tests matter more than order.
- Use a frozenset when you need set behavior but the group should stay fixed.
- Use a dictionary when each value belongs under a meaningful label.
When two structures could work, choose the one that makes the code's question obvious. scores["Mina"] tells a clearer story than searching two parallel lists for Mina's score. "Mina" in checked_in tells a clearer story than scanning a list when order does not matter.
Checkpoint
Answer all three to mark this lesson complete
You now have the full beginner collection toolbox: ordered lists, fixed tuples, labeled dictionaries, and unique sets. Next, functions let you wrap these ideas into reusable actions instead of rewriting the same steps again and again.