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, orassert not, to check that it'sFalse. - 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 justshuttle. - Try: write
is_winter, whether a row's"month"is"Jan","Feb", or"Mar", andlow_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 tofilter, which calls it. filterproduces 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
filterchecks each row on its own, so it can't answer questions that compare rows, like which winter month had the fewest riders?order_bysorts the rows by a column:ascending=Truefrom smallest to largest,ascending=Falsefrom largest to smallest. It makes a new table, without changingwinter:
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 fortest_is_high_valueto check? - What is
smallest_high_time? What would it be withascending=False? - If "high-value" meant an amount of at least 7.95, which lines would change, and how?
Class Exercise (40 mins)
- Design a function
is_morningthat 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. - 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. - Write code to extract the amount of the latest morning order.
- 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 - Now filter rows that have the subject "Forest" to create a new table.
- Order the resulting new table by date, and extract the location from the most recent row.
Wrap-up (5 mins)
- Operations on tables, like
filterandorder_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!