Skill 2: Construct/Transform Tables (Pyret)
1. Creating Tables
What to Teach
Tables are fundamental data structures in Pyret for organizing and manipulating structured data. Students need to understand both literal table creation and importing from external sources.
Creating Literal Tables
students-table = table: name :: String, age :: Number, grade :: String
row: "Alice", 18, "A"
row: "Bob", 17, "B"
row: "Charlie", 18, "A"
end
Importing from Files
Download the file sales-data.csv and then drag it into the files region of your Github.dev editor to upload it.
# Load CSV from local file in repository
sales-data = load-table: product, price, quantity
source: "sales-data.csv"
end
Teaching Examples
Good Example:
weather-data = table: city :: String, temperature :: Number, humidity :: Number
row: "Boston", 72, 65
row: "New York", 75, 70
row: "Chicago", 68, 60
end
What to Point Out:
- Column names are descriptive and follow naming conventions
- Type annotations for each column
- Consistent data types within columns
- Proper syntax with colons and commas
Common Student Mistakes to Watch For
-
Missing type annotations
# BAD - no type information
my-table = table: name, score
row: "Alice", 95
end -
Inconsistent column types
# BAD - mixing strings and numbers in same column
mixed-table = table: value :: String
row: "hello"
row: 42
end -
Syntax errors in table construction
# BAD - missing colons, wrong punctuation
bad-table = table name :: String, age :: Number
row "Alice" 18
end
2. Extracting Data from Tables
What to Teach
Students need to know how to access specific rows, columns, and individual values from tables for analysis and computation.
Extracting Single Values
# get value from specific row and column
first-student-name = students-table.row-n(0)["name"]
alice-age = students-table.row-n(0)["age"]
Extracting Rows
# get entire row as a record
first-row = students-table.row-n(0)
last-row = students-table.row-n(students-table.length() - 1)
Extracting Columns
# get all values from a column
all-names = students-table.get-column("name")
all-ages = students-table.get-column("age")
Teaching Examples
Good Example:
inventory = table: item :: String, quantity :: Number, price :: Number
row: "apples", 50, 1.20
row: "bananas", 30, 0.80
row: "oranges", 25, 1.50
end
# extract specific data
first-item = inventory.row-n(0)["item"]
apple-quantity = inventory.row-n(0)["quantity"]
all-prices = inventory.get-column("price")
What to Point Out:
- Use
row-n(index)for specific rows (0-indexed) - Use bracket notation
["column-name"]to access column values - Use
get-column("name")to extract entire columns - Remember that table indices start at 0
Common Student Mistakes to Watch For
-
Confusing row and column access
# BAD - trying to use column syntax on rows
wrong-value = my-table.get-column(0)["name"] -
Off-by-one errors with indexing
# BAD - using 1-based indexing instead of 0-based
last-item = my-table.row-n(my-table.length())
3. Table Transformation Functions
What to Teach
Pyret provides powerful built-in functions for transforming tables. Students should understand when and how to use each transformation method.
build-column
Adds a new column based on existing data:
# add calculated column
students-with-status = build-column(students-table, "status",
lam(row): if row["age"] >= 18: "adult" else: "minor" end end)
filter-with
Selects rows that match a condition:
# filter for specific criteria
adult-students = filter-with(students-table,
lam(row): row["age"] >= 18 end)
honor-students = filter-with(students-table,
lam(row): row["grade"] == "A" end)
transform-column
Modifies values in an existing column:
# transform existing column
students-upper = transform-column(students-table, "name",
lam(name): string-to-upper(name) end)
# apply mathematical transformation
prices-with-tax = transform-column(inventory, "price",
lam(price): price * 1.08 end)
Teaching Examples
Comprehensive Example:
employees = table: name :: String, salary :: Number, department :: String
row: "Alice", 50000, "Engineering"
row: "Bob", 45000, "Marketing"
row: "Charlie", 55000, "Engineering"
row: "Diana", 48000, "Sales"
end
# build new column for salary category
employees-with-category = build-column(employees, "category",
lam(row):
if row["salary"] >= 50000: "high"
else: "standard"
end
end)
# filter for engineering department
engineers = filter-with(employees,
lam(row): row["department"] == "Engineering" end)
# transform salaries to include 5% raise
employees-with-raise = transform-column(employees, "salary",
lam(salary): salary * 1.05 end)
What to Point Out:
- Each function returns a new table (doesn't modify original)
- Lambda functions (
lam) define the transformation logic build-columnadds columns,transform-columnmodifies existing onesfilter-withselects rows based on conditions
Common Student Mistakes to Watch For
-
Forgetting to use
lamfor transformation functions# BAD - missing lambda function
filtered = filter-with(my-table, row["age"] >= 18) -
Trying to modify original table
# BAD - assuming table is modified in place
transform-column(my-table, "price", lam(p): p * 2 end)
# students expects my-table to be changed -
Incorrect lambda syntax
# BAD - wrong lambda syntax
filtered = filter-with(my-table, lambda(row): row["age"] >= 18)
4. Using lam for Concise Transformations
What to Teach
Lambda functions (lam) enable concise, readable transformations. Students should understand lambda syntax and when to use it versus named functions.
Basic Lambda Syntax
# basic lambda structure
lam(parameter1, parameter2, ...): expression end
Lambda vs Named Functions
# using named function (more verbose, but works the same)
fun is-adult(row):
row["age"] >= 18
end
adults = filter-with(students-table, is-adult)
# using lambda (more concise)
adults = filter-with(students-table,
lam(row): row["age"] >= 18 end)
Teaching Examples
Simple Lambda Examples:
# double all prices
doubled-prices = transform-column(inventory, "price",
lam(price): price * 2 end)
# convert names to uppercase
upper-names = transform-column(students-table, "name",
lam(name): string-to-upper(name) end)
# or, more concisely:
upper-names2 = transform-column(students-table, "name", string-to-upper)
# add full-name column
students-with-full = build-column(students-table, "full-name",
lam(row): row["first"] + " " + row["last"] end)
Complex Lambda Examples:
# multiple conditions in filter
honor-adults = filter-with(students-table,
lam(row): (row["age"] >= 18) and (row["grade"] == "A") end)
# complex calculation in build-column
students-with-gpa = build-column(students-table, "gpa",
lam(row):
if row["grade"] == "A": 4.0
else if row["grade"] == "B": 3.0
else if row["grade"] == "C": 2.0
else: 1.0
end
end)
What to Point Out:
- Lambda functions are anonymous (no name needed)
- Use when the function is short and used only once
- Good for simple transformations and filters
- Can contain complex logic with
ifexpressions
Common Student Mistakes to Watch For
-
Using wrong lambda syntax
# BAD - using `fun` instead of `lam`
filtered = filter-with(my-table, fun(row): row["age"] >= 18 end) -
Forgetting
endkeyword# BAD - missing end
transformed = transform-column(my-table, "price", lam(p): p * 2) -
Missed opportunities
# BAD -- not wrong, but very verbose for what it is
fun double-price(price):
price * 2
end
doubled = transform-column(inventory, "price", double-price)
# BETTER - use lam for simple cases
doubled = transform-column(inventory, "price", lam(p): p * 2 end)
Common Teaching Scenarios
When Students Ask "Why use tables instead of lists?"
"Tables let you organize related data with named columns, making it easier to work with complex datasets. You can filter, transform, and analyze data more naturally."
When Students Struggle with Lambda Syntax
"Think of lam as a quick way to define a function right where you need it. The pattern is always lam(input): what-to-do-with-input end."
When Students Forget Tables Are Immutable
"Table operations return new tables - they don't change the original. Always assign the result to a variable if you want to keep the transformed data."
When Students Mix Up Row and Column Access
"Remember: row-n(index) gets a whole row, then use ["column-name"] to get a specific value. get-column("name") gets all values from that column."