When should you use a list, tuple, set, or dict?
Quick Answer
**List**: ordered, mutable, allows duplicates — general-purpose sequence. **Tuple**: ordered, immutable — fixed-size records, safe as a dict key/set element. **Set**: unordered, unique elements, O(1) membership testing — deduplication and fast "contains" checks. **Dict**: key→value mapping, O(1) lookup by key, insertion-ordered — the default choice whenever you need to look things up by a name/id rather than by position.
Detailed Answer
Quick decision table
| Need | Structure | Why |
|---|---|---|
| Ordered, mutable collection, duplicates OK | list | general-purpose sequence |
Fixed-size, immutable record ((x, y), (name, age)) | tuple | safe to hash, signals "this won't change" |
| Fast membership testing, deduplication | set | O(1) average in, automatic uniqueness |
| Lookup by key/name | dict | O(1) average lookup by key, not position |
Concrete examples
# list -- ordered sequence of items, order and duplicates matter
scores = [85, 92, 85, 78]
# tuple -- an immutable, fixed-shape record
point = (3, 4)
person = ("Ada", 36)
# set -- membership and uniqueness, order doesn't matter
seen_ids = {101, 205, 310}
if user_id in seen_ids: # O(1) average -- much faster than `in a_list` for large data
...
unique_tags = set(all_tags) # dedupe in one line
# dict -- look things up by key
users_by_id = {101: "Ada", 205: "Grace"}
users_by_id[101] # O(1) average
Why x in set beats x in list at scale
big_list = list(range(1_000_000))
big_set = set(big_list)
999_999 in big_list # O(n) -- scans up to a million elements
999_999 in big_set # O(1) average -- direct hash lookup
For any workload doing repeated membership checks against a large
collection, converting to a set (or using a dict if you also need
associated values) is one of the cheapest, highest-impact optimizations
available.
Tuple vs list: signaling intent, not just performance
def get_coordinates():
return (self.x, self.y) # a tuple signals "this is a fixed 2-item record"
Beyond being hashable (usable as dict keys/set elements) and slightly more
memory-efficient, using a tuple for a fixed-shape value communicates to
readers that the shape — not just the values — is meant to be fixed:
nobody should expect to .append() to it.
Interview-ready summary: Reach for list for ordered, mutable
sequences; tuple for fixed-shape, immutable records (and anything you
need to hash); set for uniqueness/fast membership testing; dict
whenever you look things up by key rather than by position. The
performance difference between O(n) list scans and O(1) set/dict lookups
is often the single biggest algorithmic win available in everyday code.