Skip to main content

Tuples & sets

Level 1: Level 1: Foundationseasy10 mintuplessetsuniquenessmembership

Group fixed records with tuples and track uniqueness with sets.

Why tuples and sets earn their own types

A list is your default container, but two jobs deserve a sharper tool. When a group of values forms one fixed record (a (latitude, longitude) pair, one database row, the several results a function returns), a tuple signals "this shape will not change." When you only care whether something is present or how many distinct things you saw (unique user IDs in a log, an allow-list of permitted roles), a set answers in one fast step instead of a scan.

Tuples: fixed records

A tuple is an ordered, immutable sequence. You index it like a list, but you cannot reassign, append to, or grow it after creation:

point = (3, 4)
point[0]        # 3
x, y = point    # unpack: x = 3, y = 4

That unpacking is why functions return tuples to hand back several values at once. divmod(17, 5) returns (3, 2), and you can catch it as q, r = divmod(17, 5). A tuple of hashable values is itself hashable, so tuples can live inside a set or serve as dict keys (lists cannot).

Sets: a hash table of unique keys

A set is an unordered collection of unique, hashable values, backed by the same hash table that powers dict keys. Duplicates collapse on the way in, and membership is answered by hashing, not scanning:

seen = {1, 2, 2, 3}      # stored as {1, 2, 3}
3 in seen                # True
len(set([1, 2, 2, 3]))   # 3   distinct count
Check yourself
You start a collection of ids you have already seen with seen = {} and then call seen.add(7). What happens?

Wrapping a list in set(...) is the idiomatic way to drop duplicates or count distinct values.

When to use which

  • tuple: a small fixed record whose fields will not change.
  • set: you care about uniqueness or membership, not order or position.
Check yourself
You write point = (3) and then call len(point). What happens?

Braces and parentheses are overloaded in Python, and the literal you write is not always the type you get:

Table
Two of these six produce a different type than the shape suggests. Both are ordinary beginner bugs that fail late, because (3) and {} are perfectly valid values and only misbehave once something tries to iterate or add to them.
You writeYou getWatch out for
[1, 2]listmutable, so it can never go inside a set
(1, 2)tupleimmutable and hashable, so it can
(3)the int 3, not a tuplea one-element tuple needs the comma: (3,)
{1, 2}setunordered; my_set[0] raises TypeError
{}an empty dict, not a setuse set() when you want an empty set
{a: 1} with real quotes on the keydictbraces mean dict the moment a colon appears
Two of these six produce a different type than the shape suggests. Both are ordinary beginner bugs that fail late, because (3) and {} are perfectly valid values and only misbehave once something tries to iterate or add to them.

Pitfalls

  • Empty braces {} make an empty dict, not a set. Use set() for an empty set.
  • A one-element tuple needs a trailing comma. (3) is just the integer 3; (3,) is a tuple.
  • Sets are unordered. Never rely on iteration order or index a set (my_set[0] raises TypeError). If you need order, sort into a list.
  • Set elements must be hashable, so a set of lists fails, but a set of tuples works.
Check yourself
A loop runs a million times and each pass evaluates x in c. Which container keeps that loop fast?

Interview nuance: membership cost is the reason to reach for a set. x in some_list is O(n) because Python checks each element in turn, while x in some_set is O(1) on average because it hashes straight to a bucket. That is exactly why counting distinct values through a set beats comparing every pair, and why de-duplication loops that build a set as they go run in linear time.

Worked example (Python)
nums = [1, 2, 2, 3, 3, 3]
print(len(set(nums)))   # 3   distinct values
print(2 in set(nums))   # True

point = (3, 4)
x, y = point
print(x, y)             # 3 4

Apply

Your turn

The task this lesson builds to.

Implement unique_count(arr): return how many distinct values are in the list arr.

For [1, 2, 2, 3] return 3.

2 hints and 4 automated checks are waiting in the workspace.

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Implement min_max(arr): return a tuple (smallest, largest) of the list arr.

For [3, 1, 5, 2] return (1, 5).

2 hints and 4 automated checks are waiting in the workspace.