Skip to main content

Class 8 - Functions over rows

Date: September 24, 2026

⚠️Homework
Homework 2 due September 27, 2026

Reference

For all work with tables, refer to the Tables page in the menu at the top of the page!

Skills: 0, 1, 3​

Notes (review before class)​

Functions over Rows​

A function can ask a question about a row. Rows are dicts, so that's the annotation for its input:

def cleared_1k(r: dict) -> bool:
"""determine whether given row has at least 1000 riders"""
return r["riders"] >= 1000

def test_cleared_1k():
assert cleared_1k(shuttle.row(2))
assert not cleared_1k(shuttle.row(3))
  • A function that returns a boolean can be tested by asserting its result directly, or assert not, to check that it's False.
  • Taking a row, rather than a position (cleared_1k(2)), is more flexible: it works on a row from any table with a "riders" column, not just shuttle.
  • Try: write is_winter, whether a row's "month" is "Jan", "Feb", or "Mar", and low_winter, whether it's a winter row with fewer than 1050 riders. Then show how the directory evolves as one of your tests runs.

Finding Rows: filter​

  • Checking rows one position at a time (if shuttle.row(0)["riders"] < 1000: ... elif shuttle.row(1)...) is painful for thousands of rows, finds only one match, and has no clear answer when nothing matches.
  • Instead, write the question as a function from a row to a boolean, and give it to the table method filter, which calls it on each row, one at a time:
def below_1k(r: dict) -> bool:
"""determine whether row has fewer than 1000 riders"""
return r["riders"] < 1000

def test_below_1k():
assert not below_1k(shuttle.row(2))
assert below_1k(shuttle.row(3))

shuttle.filter(below_1k)
  • No parentheses after below_1k: we aren't calling it, we're giving it to filter, which calls it.
  • filter produces a table of all the matching rows, which we can name:
winter = shuttle.filter(is_winter)  # the Jan, Feb, and Mar rows

Ordering Rows: order_by​

  • filter checks each row on its own, so it can't answer questions that compare rows, like which winter month had the fewest riders?
  • order_by sorts the rows by a column: ascending=True from smallest to largest, ascending=False from largest to smallest. It makes a new table, without changing winter:
winter.order_by("riders", ascending=True)  # Feb, then Mar, then Jan
  • Combine operations to answer a question: find rows (filter), order them (order_by), take a row (row), then a cell ([...]), as we combined image operations. All at once, or naming each step (adding names to the directory):
winter.order_by("riders", ascending=True).row(0)["month"]  # -> 'Feb'

sorted_winter = winter.order_by("riders", ascending=True)
least_row = sorted_winter.row(0)
least_row["month"] # -> 'Feb'

Recap (15 mins)​

A coffee cart records the time and amount of each order. Read through the program, which finds the high-value orders (an amount of at least 8):

orders = table(
["time", "amount"],
[
["08:00", 10.50],
["09:30", 5.75],
["10:15", 8.00],
["11:00", 3.95],
["14:00", 4.95],
["16:45", 7.95],
],
)

def is_high_value(r: dict) -> bool:
"""returns whether the amount column is >= 8"""
return r["amount"] >= 8.0

def test_is_high_value():
assert is_high_value(orders.row(2))
assert not is_high_value(orders.row(3))

high_value_orders = orders.filter(is_high_value)

def test_high_value_orders():
assert high_value_orders == table(
["time", "amount"],
[
["08:00", 10.50],
["10:15", 8.00],
],
)

smallest_high_time = high_value_orders.order_by("amount", ascending=True).row(0)["time"]
  • Why is orders.row(2) a good row for test_is_high_value to check?
  • What is smallest_high_time? What would it be with ascending=False?
  • If "high-value" meant an amount of at least 7.95, which lines would change, and how?

Class Exercise (40 mins)​

  1. Design a function is_morning that checks if the "time" column in a row represents a morning. Note that < works for strings, using "lexicographic" (i.e., character by character) ordering. Now produce a new table that is only morning orders.
  2. Create a table where the orders are sorted by time from latest to earliest, rather than how the original table is sorted. Use order_by, rather than constructing it by hand.
  3. Write code to extract the amount of the latest morning order.
  4. Load the data from the following url (see notes from yesterday for review): https://raw.githubusercontent.com/neu-pdi/cs2000-public-resources/refs/heads/main/static/support/7-photos.csv
  5. Now filter rows that have the subject "Forest" to create a new table.
  6. Order the resulting new table by date, and extract the location from the most recent row.

Wrap-up (5 mins)​

  • Operations on tables, like filter and order_by, allow us to easily use code to work with large sets of data by restricting to certain subsets and re-ordering them.
  • Next class we'll see how else we can transform tables!