Programming, problem solving, and algorithms

CPSC 203, 2026 W1

October 15, 2026

Announcements

  • Examlet 2 runs through Sunday.
  • Lab 5 (matplotlib and pandas) and POTW 5 (pandas and matplotlib) due Sunday.
  • Project 1 due Monday, October 26 (~1½ weeks).

Dictionary Patterns

Not Just a One-Trick Pony

Dictionaries / key-value lookup is useful for solving other common problems.

  • Compound data.
  • Tracking membership.
  • Counting appearances / frequencies.
  • Finding complements.
  • Grouping by (discrete) category.
  • Representing a map or translation over a discrete domain.

Last two classes: First five patterns.

Today: Translation / mapping.

Common Pattern: Translation/Mapping

Use case: Convert values from one representation to another.


Example: Go through a string and replace any word which has an emoji equivalent.


Example: Substitution cypher.

word emoji
sun ☀️
rain 🌧️
cloud ☁️
happy 😊
sad 😢
love ❤️
cat 🐱
dog 🐶
coffee ☕

Let’s Practice!

Open today’s activity. You’ll solve 2 new puzzles.

Summary

Dictionaries give you fast lookup by key — whether you have 100 items or 100,000.

Pattern Use Case Technique
Record Store named fields {"name": ..., "age": ...}
Membership Track what we’ve seen seen[x] = True
Counting Count occurrences Counter(items)
Complement Find pairs Store & check complements
Grouping Organize by category defaultdict(list)
Translation Convert values Direct key → value mapping

Oh No!

In CPSC 103 / 110: One code template for each data type.

In CPSC 203:

  • Compound data could be stored as NamedTuples / DataClasses, lists / tuples, or dictionaries.
    • Slightly different syntax, but same basic template.
  • Key-value pairs can be stored as dictionaries.
    • Notably different code template depending on the task.
    • Sometimes the problem information is not in the form of a key-value pair.

Aside: Python Magic Methods

Python Magic Methods

Remember: Any piece of data in Python is an object that belongs to a class.

You will often see references to methods with two underscore characters before and after the name; for example, __init__(), __str__(), __len()__.

  • Called dunder (short for double underscore) or magic methods.
  • Do not make up your own method names with the double underscore notation.
  • You can definitely implement these methods for your own classes.

Example Magic Methods

Magic methods are used by Python to implement internal behaviours and operator overloading.

  • When you call print(x), Python displays the result of x.__str__().
  • When you call len(x), Python returns the result of x.__len__().
  • When you write x + y, Python will call x.__add__(y).
  • When you write x[i], Python will call x.__getitem__(i).
  • When you write x[i] = y, Python will call x.__setitem__(i, y).
  • …

Aside: Class Hierarchies and Interfaces

Class Hierarchies

Remember: Any piece of data in Python is an object that belongs to a class.

When we have a bunch of related classes, we often organize them in a hierarchy.

  • Classes have a parent or superclass from which they inherit attributes and methods.
    • If a class definition does not list a superclass, then it inherits from Python’s object class.
  • Classes can have children or subclasses which implement (or even change) their methods and attributes.

Why Class Hierarchies?

Conceptually, the idea is that you can work with an object as if it was an instance of the parent class rather than needing to know to which specific child class it belongs.

In particular, different children might:

  • Store their data in different ways.
  • Store different data.
  • Implement the same method in different ways.

But the user only needs to know the common method’s signature (typically given in the parent class).

Class Hierarchy Example

Interfaces

A contract specifying which method(s) a child class should implement.

  • An interface is not a class.
  • It provides only the signature(s) of the required method(s), not implementation(s).
  • You cannot create an object instantiating an interface.

You can create classes which inherit from / implement an interface.

  • Make sure that the class implements the required method(s).
  • When you instantiate an object, it will implement the interface.

Useful Interface: iterable

  • Intuition: If you can write a for loop over the elements of the object.
  • Contract: Object implements the __iter__(self) method.
  • Practical effects:
    • You can write loops: for item in x: ...
    • You can write list comprehensions.
    • You can trivially convert to a list: list(x) or tuple(x).

Examples of iterable

Examples:

  • list, tuple, str. Elements will always come out in the same order in which they were created.
  • set. Elements may come out in a different order.
  • dict. The iteration is over the keys, and elements may come out in a different order.
  • The objects returned by range() and enumerate().
  • Files, pandas Series and DataFrames, and many more.

Useful Interface: hashable

  • Intuition: An object that is immutable.
  • Contract: Object implements the __hash__(self) and __eq__(self, other) methods.
  • Technical details: A magic number (the hash value) with a constant number of digits can be computed from the object such that:
    • You will always get the same number for this object.
    • You will (almost) always get a different number for any other object.
  • Practical effects:
    • The object can be used as a key in a dictionary or added to a set.
    • The programmer need not worry about aliasing or function side-effects.

Examples of hashable

  • All the simple atomic types: int, str, bool, float, NoneType.
  • NamedTuples (but not dataclasses).
  • Many basic mutable types have an immutable version.
    • For example: tuple, frozenset, (as of Python 3.15) frozendict.
  • The union of other immutable types.
    • For example, optional type: some_type | None.