Skip to main content

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

  1. Missing type annotations

    # BAD - no type information
    my-table = table: name, score
    row: "Alice", 95
    end
  2. Inconsistent column types

    # BAD - mixing strings and numbers in same column
    mixed-table = table: value :: String
    row: "hello"
    row: 42
    end
  3. 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

  1. Confusing row and column access

    # BAD - trying to use column syntax on rows
    wrong-value = my-table.get-column(0)["name"]
  2. 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-column adds columns, transform-column modifies existing ones
  • filter-with selects rows based on conditions

Common Student Mistakes to Watch For

  1. Forgetting to use lam for transformation functions

    # BAD - missing lambda function
    filtered = filter-with(my-table, row["age"] >= 18)
  2. 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
  3. 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 if expressions

Common Student Mistakes to Watch For

  1. Using wrong lambda syntax

    # BAD - using `fun` instead of `lam`
    filtered = filter-with(my-table, fun(row): row["age"] >= 18 end)
  2. Forgetting end keyword

    # BAD - missing end
    transformed = transform-column(my-table, "price", lam(p): p * 2)
  3. 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."