Standard Library: Table

Work with tables (dataframes)

For more information on tables see the language reference.


Module Contents


Table.average(table)

weather = #{
  date         , city           , low , high
  "2025-12-15" , "boston"       ,  14 ,   25
  "2025-12-15" , "philadelphia" ,  20 ,   28
  "2025-12-16" , "boston"       ,  23 ,   36
  "2025-12-16" , "philadelphia" ,  20 ,   35
  "2025-12-17" , "boston"       ,  29 ,   47
  "2025-12-17" , "philadelphia" ,  26 ,   46
  "2025-12-18" , "boston"       ,  30 ,   47
  "2025-12-18" , "philadelphia" ,  30 ,   56
  "2025-12-19" , "boston"       ,  36 ,   59
  "2025-12-19" , "philadelphia" ,  31 ,   61
}

Table.average(weather)
{ low: 25.9, high: 44 }
Table.summarize(weather, "city", Table.average)
┌──────────────┬──────┬──────┐
│ city         │ low  │ high │ x 2
├──────────────┼──────┼──────┤
│ boston       │ 26.4 │ 42.8 │
│ philadelphia │ 25.4 │ 45.2 │
└──────────────┴──────┴──────┘

Table.bottom(table, columns, count)

Sort table in ascending order by columns and take the first count rows of the sorted table. Equivalent to take(sortBy(table, columns), count).

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
}

Table.bottom(cities, "population", 4)
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 4
├──────────────┼───────┼────────────┤
│ Dallas       │ TX    │    1326087 │
│ San Diego    │ CA    │    1404452 │
│ San Antonio  │ TX    │    1526656 │
│ Philadelphia │ PA    │    1573916 │
└──────────────┴───────┴────────────┘

Table.columns(table)

Get the column names in table as a list.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
}

Table.columns(cities)
["city", "state"]

Table.count(table, matcher)

cities = #{
  city           , state
  "Houston"      , "TX"
  "Phoenix"      , "AZ"
  "Philadelphia" , "PA"
  "San Antonio"  , "TX"
}

Table.count(cities, { state: "TX" })
2

Table.countAll(table)

Return a table containing deduplicated rows of table. Each row will have two additional entries, count and share, which will contain the number of copies of each row in the original table, and the fraction of the total rows that this count represents. The original table may not contain columns named count or share.

locations = #{
  city          , state
  "New York"    , "NY"
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "New York"    , "NY"
  "Houston"     , "TX"
  "Houston"     , "TX"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
}

Table.countAll(locations)
┌─────────────┬───────┬───────┬───────┐
│ city        │ state │ count │ share │ x 4
├─────────────┼───────┼───────┼───────┤
│ New York    │ NY    │     3 │ 0.375 │
│ Los Angeles │ CA    │     2 │ 0.250 │
│ Houston     │ TX    │     2 │ 0.250 │
│ Chicago     │ IL    │     1 │ 0.125 │
└─────────────┴───────┴───────┴───────┘

Table.defaultCols(table, columns)

If table has zero columns (and therefore by definition zero rows), return an empty table with the given columns. If table has columns then return table.

This is useful when you're making a table from a list of rows that may or may not be empty, and you want to make sure your table ends up with the correct columns.

players = #{
  name    , yards
  "Lamar" ,  4172
  "Josh"  ,  3731
}

Table.defaultCols(players, ["name", "yards"])

players = #{}

Table.defaultCols(players, ["name", "yards"])
┌───────┬───────┐
│ name  │ yards │ x 2
├───────┼───────┤
│ Lamar │  4172 │
│ Josh  │  3731 │
└───────┴───────┘
┌──────┬───────┐
│ name │ yards │ x 0
└──────┴───────┘

Table.drop(table, count)

Remove the first count rows from table.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
  "Phoenix"     , "AZ"
}

drop(cities, 3)
┌─────────┬───────┐
│ city    │ state │ x 2
├─────────┼───────┤
│ Houston │ TX    │
│ Phoenix │ AZ    │
└─────────┴───────┘

(Accessible as a global through Overloads.drop)


Table.dropLast(table, count)

Remove the last count rows from table.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
  "Phoenix"     , "AZ"
}

Table.dropLast(cities, 3)
┌─────────────┬───────┐
│ city        │ state │ x 2
├─────────────┼───────┤
│ New York    │ NY    │
│ Los Angeles │ CA    │
└─────────────┴───────┘

Table.filter(table, condition)

Keep the rows in table that satisfy condition.

cities = #{
  city           , state
  "Houston"      , "TX"
  "Phoenix"      , "AZ"
  "Philadelphia" , "PA"
  "San Antonio"  , "TX"
  "San Diego"    , "CA"
  "Dallas"       , "TX"
}

Table.filter(cities, fn(city) city.state == "TX" end)
┌─────────────┬───────┐
│ city        │ state │ x 3
├─────────────┼───────┤
│ Houston     │ TX    │
│ San Antonio │ TX    │
│ Dallas      │ TX    │
└─────────────┴───────┘

Note that this can also be accomplished using the filter ? operator.

cities ? arg.state == "TX"
┌─────────────┬───────┐
│ city        │ state │ x 3
├─────────────┼───────┤
│ Houston     │ TX    │
│ San Antonio │ TX    │
│ Dallas      │ TX    │
└─────────────┴───────┘

Table.focus(table, columns)

Reorder the columns in table so that the given columns appear first, in the given order. columns may be a single string (for one column) or a list of strings (for multiple columns).

players = #{
  name    , yards , tds, ints
  "Lamar" ,  4172 ,  41,    4
  "Josh"  ,  3731 ,  28,    6
}

Table.focus(players, ["yards", "name"])
Table.focus(players, "ints")
┌───────┬───────┬─────┬──────┐
│ yards │ name  │ tds │ ints │ x 2
├───────┼───────┼─────┼──────┤
│  4172 │ Lamar │  41 │    4 │
│  3731 │ Josh  │  28 │    6 │
└───────┴───────┴─────┴──────┘
┌──────┬───────┬───────┬─────┐
│ ints │ name  │ yards │ tds │ x 2
├──────┼───────┼───────┼─────┤
│    4 │ Lamar │  4172 │  41 │
│    6 │ Josh  │  3731 │  28 │
└──────┴───────┴───────┴─────┘

Table.get(table, selector)

Get the row or column from table that corresponds to selector, where selector may be a number, string, or object.

  • If selector is a number, return the row at index selector.

  • If selector is an object, return the first row that matches selector, with the requirement that at least one row matches.

  • If selector is a string, return the values from the column with name selector as a list.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
}

Table.get(cities, 1)
Table.get(cities, { state: "TX" })
Table.get(cities, "city")
{ city: "Los Angeles", state: "CA" }
{ city: "Houston", state: "TX" }
["New York", "Los Angeles", "Chicago", "Houston"]

Note that these operations can also be performed using the index [] and field . operators.

cities[1]
cities[{ state: "TX" }]
cities.city
cities["city"]
{ city: "Los Angeles", state: "CA" }
{ city: "Houston", state: "TX" }
["New York", "Los Angeles", "Chicago", "Houston"]
["New York", "Los Angeles", "Chicago", "Houston"]

Table.group(table, columns)

Partition table into groups based on the values in columns, which may be a string (single column) or a list of strings (multiple columns).

Rows with the same values in the given columns are grouped together. The result is a list of tables, each containing the rows for one group.

cities = #{
  city           , state
  "New York"     , "NY"
  "Los Angeles"  , "CA"
  "Chicago"      , "IL"
  "Houston"      , "TX"
  "Phoenix"      , "AZ"
  "Philadelphia" , "PA"
  "San Antonio"  , "TX"
  "San Diego"    , "CA"
  "Dallas"       , "TX"
}

Table.group(cities, "state")
[
  ┌──────────┬───────┐
  │ city     │ state │ x 1
  ├──────────┼───────┤
  │ New York │ NY    │
  └──────────┴───────┘,
  ┌─────────────┬───────┐
  │ city        │ state │ x 2
  ├─────────────┼───────┤
  │ Los Angeles │ CA    │
  │ San Diego   │ CA    │
  └─────────────┴───────┘,
  ┌─────────┬───────┐
  │ city    │ state │ x 1
  ├─────────┼───────┤
  │ Chicago │ IL    │
  └─────────┴───────┘,
  ┌─────────────┬───────┐
  │ city        │ state │ x 3
  ├─────────────┼───────┤
  │ Houston     │ TX    │
  │ San Antonio │ TX    │
  │ Dallas      │ TX    │
  └─────────────┴───────┘,
  ┌─────────┬───────┐
  │ city    │ state │ x 1
  ├─────────┼───────┤
  │ Phoenix │ AZ    │
  └─────────┴───────┘,
  ┌──────────────┬───────┐
  │ city         │ state │ x 1
  ├──────────────┼───────┤
  │ Philadelphia │ PA    │
  └──────────────┴───────┘,
]

Table.has(table, selector)

Check whether table contains a column or row that matches selector, which may be either a string or an object.

  • If selector is a string, check whether table has a column named selector.
  • If selector is an object, check whether table has a row which matches selector.
cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
}

Table.has(cities, "city")
Table.has(cities, "county")

Table.has(cities, { state: "NY" })
Table.has(cities, { state: "VT" })
true
false
true
false

Note that this can also be accomplished using the in operator.

"city" in cities
"county" in cities

{ state: "NY" } in cities
{ state: "VT" } in cities
true
false
true
false

Table.indexOf(table, matcher)

Get the index of the first row in table that matches the object matcher, or none if no row matches.

cities = #{
  city           , state
  "Houston"      , "TX"
  "Phoenix"      , "AZ"
  "Philadelphia" , "PA"
  "San Antonio"  , "TX"
}

Table.indexOf(cities, { state: "TX" })
Table.indexOf(cities, { state: "FL" })
0
none

Table.isEmpty(table)

Check whether table is empty (has 0 rows). Note that an empty table may still have one or more columns.

isEmpty(#{
  name    , yards
  "Lamar" ,  4172
  "Josh"  ,  3731
})

isEmpty(#{
  name , yards
})
false
true

(Accessible as a global through Overloads.isEmpty)


Table.join(tableA, tableB, columns)

Perform an inner join of tableA and tableB using columns. columns may be a single string (for one column) or a list of strings (for multiple columns).

Find all the pairs of rows (one row from each table) with matching values in columns. Merge each of these rows and create a new table of the resulting rows.

donors = #{
  donor      , type
  "Luna"     , "O"
  "Marty"    , "B"
  "Mercedes" , "A"
}

recipients = #{
  recipient  , type
  "Judy"     , "O"
  "DeVondre" , "O"
  "Sammy"    , "B"
}

Table.join(donors, recipients, "type")
┌───────┬──────┬───────────┐
│ donor │ type │ recipient │ x 3
├───────┼──────┼───────────┤
│ Luna  │ O    │ Judy      │
│ Luna  │ O    │ DeVondre  │
│ Marty │ B    │ Sammy     │
└───────┴──────┴───────────┘

Table.joinGroup(tableA, tableB, columns, reducer)

purchases = #{
  item        , quantity
  "tea"       ,        2
  "FIREWORKS" ,        4
  "cereal"    ,        2
  "rice"      ,        1
  "candles"   ,      600
  "tea"       ,        3
  "rice"      ,        1
}

items = #{
  item        , price
  "tea"       ,     5
  "cereal"    ,     6
  "candles"   ,     6
  "rice"      ,    20
  "diet coke" ,     2
}

fn totalSpending(item, purchases)
  item.quantity = sum(purchases.quantity)
  item.total = item.price * item.quantity
  item
end

Table.joinGroup(items, purchases, "item", totalSpending)
┌───────────┬───────┬──────────┬───────┐
│ item      │ price │ quantity │ total │ x 5
├───────────┼───────┼──────────┼───────┤
│ tea       │     5 │        5 │    25 │
│ cereal    │     6 │        2 │    12 │
│ candles   │     6 │      600 │  3600 │
│ rice      │    20 │        2 │    40 │
│ diet coke │     2 │        0 │     0 │
└───────────┴───────┴──────────┴───────┘

Table.joinLeft(tableA, tableB, columns)

cities = #{
  city          , state
  "Philadephia" , "PA"
  "Austin"      , "TX"
  "Boston"      , "MA"
  "Cleveland"   , "OH"
}

regions = #{
  state , region
  "MA"  , "New England"
  "MA"  , "North East"
  "PA"  , "Mid Atlantic"
  "TX"  , "Southwest"
}

Table.joinLeft(cities, regions, "state")
┌─────────────┬───────┬──────────────┐
│ city        │ state │ region       │ x 5
├─────────────┼───────┼──────────────┤
│ Philadephia │ PA    │ Mid Atlantic │
│ Austin      │ TX    │ Southwest    │
│ Boston      │ MA    │ New England  │
│ Boston      │ MA    │ North East   │
│ Cleveland   │       │              │
└─────────────┴───────┴──────────────┘

Table.len(table)

Get the number of rows in table.

players = #{
  name    , yards
  "Lamar" ,  4172
  "Josh"  ,  3731
}

len(players)
2

(Accessible as a global through Overloads.len)


Table.map(table, func)

Transform each row in table using func.

players = #{
  name    , yards , tds, ints
  "Lamar" ,  4172 ,  41,    4
  "Josh"  ,  3731 ,  28,    6
}

fn addTD(player)
  player.tds += 1
  player
end

Table.map(players, addTD)
┌───────┬───────┬─────┬──────┐
│ name  │ yards │ tds │ ints │ x 2
├───────┼───────┼─────┼──────┤
│ Lamar │  4172 │  42 │    4 │
│ Josh  │  3731 │  29 │    6 │
└───────┴───────┴─────┴──────┘

Note that this can also be accomplished using the map $ operator along with Table.of.

players $ addTD | Table.of
┌───────┬───────┬─────┬──────┐
│ name  │ yards │ tds │ ints │ x 2
├───────┼───────┼─────┼──────┤
│ Lamar │  4172 │  42 │    4 │
│ Josh  │  3731 │  29 │    6 │
└───────┴───────┴─────┴──────┘

Table.match(table, matcher)

Filter table to contain only the rows which match the object matcher.

cities = #{
  city           , state
  "Houston"      , "TX"
  "Phoenix"      , "AZ"
  "Philadelphia" , "PA"
  "San Antonio"  , "TX"
}

Table.match(cities, { state: "TX" })
┌─────────────┬───────┐
│ city        │ state │ x 2
├─────────────┼───────┤
│ Houston     │ TX    │
│ San Antonio │ TX    │
└─────────────┴───────┘

Table.max(table)

weather = #{
  date         , city           , low , high
  "2025-12-02" , "boston"       ,  29 ,   36
  "2025-12-02" , "philadelphia" ,  32 ,   42
  "2025-12-04" , "boston"       ,  18 ,   40
  "2025-12-04" , "philadelphia" ,  29 ,   43
}

max(weather)
{ low: 32, high: 43 }
Table.summarize(weather, "city", max)
┌──────────────┬─────┬──────┐
│ city         │ low │ high │ x 2
├──────────────┼─────┼──────┤
│ boston       │  29 │   40 │
│ philadelphia │  32 │   43 │
└──────────────┴─────┴──────┘

(Accessible as a global through Overloads.max)


Table.maxAll(table, columns)

Get a table containing all the rows in table for which select(table, columns) is maximized. See the docs for Table.sortBy for details on the ranking process.

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
}

Table.maxAll(cities, "state")
┌─────────────┬───────┬────────────┐
│ city        │ state │ population │ x 3
├─────────────┼───────┼────────────┤
│ Houston     │ TX    │    2390125 │
│ San Antonio │ TX    │    1526656 │
│ Dallas      │ TX    │    1326087 │
└─────────────┴───────┴────────────┘

Table.maxBy(table, columns)

Get the row with the largest values in columns where columns may be a string (single column) or a list of strings (multiple columns). In other words, get the row that would come first if table were sorted by columns in descending order.

See the docs for Table.sortBy for details on the sorting process.

cities = #{
  city           , state , population
  "New York"     , "NY"  ,    8478072
  "Los Angeles"  , "CA"  ,    3878704
  "Chicago"      , "IL"  ,    2721308
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
}

Table.maxBy(cities, "population")
Table.maxBy(cities, ["state", "city"])
{ city: "New York", state: "NY", population: 8478072 }
{ city: "Houston", state: "TX", population: 2390125 }

Table.merge(tables)

Merge (flatten) a list of tables into a single table.

t1 = #{
  city      , state
  "Houston" , "TX"
  "Phoenix" , "AZ"
}

t2 = #{
  city           , state
  "Philadelphia" , "PA"
  "San Antonio"  , "TX"
}

Table.merge([t1, t2])
┌──────────────┬───────┐
│ city         │ state │ x 4
├──────────────┼───────┤
│ Houston      │ TX    │
│ Phoenix      │ AZ    │
│ Philadelphia │ PA    │
│ San Antonio  │ TX    │
└──────────────┴───────┘

Note that tables can also be merged using the + operator.

t1 + t2
┌──────────────┬───────┐
│ city         │ state │ x 4
├──────────────┼───────┤
│ Houston      │ TX    │
│ Phoenix      │ AZ    │
│ Philadelphia │ PA    │
│ San Antonio  │ TX    │
└──────────────┴───────┘

Table.min(table)

weather = #{
  date         , city           , low , high
  "2025-12-02" , "boston"       ,  29 ,   36
  "2025-12-02" , "philadelphia" ,  32 ,   42
  "2025-12-04" , "boston"       ,  18 ,   40
  "2025-12-04" , "philadelphia" ,  29 ,   43
}

min(weather)
{ low: 18, high: 36 }
Table.summarize(weather, "city", min)
┌──────────────┬─────┬──────┐
│ city         │ low │ high │ x 2
├──────────────┼─────┼──────┤
│ boston       │  18 │   36 │
│ philadelphia │  29 │   42 │
└──────────────┴─────┴──────┘

(Accessible as a global through Overloads.min)


Table.minAll(table, columns)

Get a table containing all the rows in table for which select(table, columns) is minimized. See the docs for Table.sortBy for details on the ranking process.

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
}

Table.minAll(cities, "state")
┌─────────┬───────┬────────────┐
│ city    │ state │ population │ x 1
├─────────┼───────┼────────────┤
│ Phoenix │ AZ    │    1673164 │
└─────────┴───────┴────────────┘

Table.minBy(table, columns)

Get the row with the smallest values in columns where columns may be a string (single column) or a list of strings (multiple columns). In other words, get the row that would come first if table were sorted by columns in ascending order.

See the docs for Table.sortBy for details on the sorting process.

cities = #{
  city           , state , population
  "New York"     , "NY"  ,    8478072
  "Los Angeles"  , "CA"  ,    3878704
  "Chicago"      , "IL"  ,    2721308
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
}

Table.minBy(cities, "population")
Table.minBy(cities, ["state", "city"])
{ city: "Philadelphia", state: "PA", population: 1573916 }
{ city: "Phoenix", state: "AZ", population: 1673164 }

Table.new(columns)

Create an empty table with the given columns.

Table.new(["name", "yards", "tds", "ints"])
┌──────┬───────┬─────┬──────┐
│ name │ yards │ tds │ ints │ x 0
└──────┴───────┴─────┴──────┘

Table.of(value)

Create a table from value, where value may be an object, a list or set of objects, a string in CSV format, or a table.

  • If value is an object, the keys become column names, and the values become the data for each column.

    • List values are used directly as the table's column data, and must all be the same length.
    • Non-list values are repeated across all rows.
  • If value is a list or set of objects, these objects become the rows of the table. The objects must have the same keys, which become the column names. Note that a table with no columns will always have zero rows.

  • If value is a table, return it.

Table.of({
  name: ["Lamar", "Josh"],
  pos: "qb",
  yards: [4172, 3731],
  tds: [41, 28],
  ints: [4, 6],
})

Table.of([
  { name: "Lamar", pos: "qb", yards: 4172, tds: 41, ints: 4 },
  { name: "Josh", pos: "qb", yards: 3731, tds: 28, ints: 6 }
])
┌───────┬─────┬───────┬─────┬──────┐
│ name  │ pos │ yards │ tds │ ints │ x 2
├───────┼─────┼───────┼─────┼──────┤
│ Lamar │ qb  │  4172 │  41 │    4 │
│ Josh  │ qb  │  3731 │  28 │    6 │
└───────┴─────┴───────┴─────┴──────┘
┌───────┬─────┬───────┬─────┬──────┐
│ name  │ pos │ yards │ tds │ ints │ x 2
├───────┼─────┼───────┼─────┼──────┤
│ Lamar │ qb  │  4172 │  41 │    4 │
│ Josh  │ qb  │  3731 │  28 │    6 │
└───────┴─────┴───────┴─────┴──────┘

Table.pop(table)

Remove the last row from table.

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
}

Table.pop(cities)
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 3
├──────────────┼───────┼────────────┤
│ Houston      │ TX    │    2390125 │
│ Phoenix      │ AZ    │    1673164 │
│ Philadelphia │ PA    │    1573916 │
└──────────────┴───────┴────────────┘

Table.product(tables)

Get the cartesian product of a list of tables. The result of product([tableA, tableB, tableC, ...]) will be a table containing a row rowA + rowB + rowC + ... for each combination of rows from the tables. The input tables should all have different keys.

ranks = #{
  rank
  "A"
  "2"
  "3"
}

suits = #{
  name       , symbol
  "Clubs"    , ""
  "Diamonds" , ""
  "Hearts"   , ""
  "Spades"   , ""
}

Table.product([ranks, suits])
┌──────┬──────────┬────────┐
│ rank │ name     │ symbol │ x 12
├──────┼──────────┼────────┤
│ A    │ Clubs    │ ♣      │
│ A    │ Diamonds │ ♦      │
│ A    │ Hearts   │ ♥      │
│ A    │ Spades   │ ♠      │
│ "2"  │ Clubs    │ ♣      │
│ "2"  │ Diamonds │ ♦      │
│ "2"  │ Hearts   │ ♥      │
│ "2"  │ Spades   │ ♠      │
│ "3"  │ Clubs    │ ♣      │
│ "3"  │ Diamonds │ ♦      │
│ "3"  │ Hearts   │ ♥      │
│ "3"  │ Spades   │ ♠      │
└──────┴──────────┴────────┘

Table.push(table, row)

Add row to the end of table. The keys in row must match the columns in table.

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
}

push(cities, { city: "San Antonio", state: "TX", population: 1526656 })
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 4
├──────────────┼───────┼────────────┤
│ Houston      │ TX    │    2390125 │
│ Phoenix      │ AZ    │    1673164 │
│ Philadelphia │ PA    │    1573916 │
│ San Antonio  │ TX    │    1526656 │
└──────────────┴───────┴────────────┘

(Accessible as a global through Overloads.push)


Table.remove(table, selector)

Remove columns or rows matching selector from table, where selector may be a string, list of strings, or object.

  • If selector is a string, remove the single column with that name.

  • If selector is a list of strings, remove all columns listed in selector.

  • If selector is an object, remove all rows which match selector.

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
}

remove(cities, "population")
remove(cities, ["city", "population"])
remove(cities, { state: "TX" })
┌──────────────┬───────┐
│ city         │ state │ x 6
├──────────────┼───────┤
│ Houston      │ TX    │
│ Phoenix      │ AZ    │
│ Philadelphia │ PA    │
│ San Antonio  │ TX    │
│ San Diego    │ CA    │
│ Dallas       │ TX    │
└──────────────┴───────┘
┌───────┐
│ state │ x 6
├───────┤
│ TX    │
│ AZ    │
│ PA    │
│ TX    │
│ CA    │
│ TX    │
└───────┘
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 3
├──────────────┼───────┼────────────┤
│ Phoenix      │ AZ    │    1673164 │
│ Philadelphia │ PA    │    1573916 │
│ San Diego    │ CA    │    1404452 │
└──────────────┴───────┴────────────┘

(Accessible as a global through Overloads.remove)


Table.rename(table, oldToNew)

For every old: new entry in the object oldToNew, rename the column in table with the name old to have the name new.

players = #{
  name    , yards , tds, ints
  "Lamar" ,  4172 ,  41,    4
  "Josh"  ,  3731 ,  28,    6
}

Table.rename(players, { tds: "touchdowns", ints: "interceptions" })
┌───────┬───────┬────────────┬───────────────┐
│ name  │ yards │ touchdowns │ interceptions │ x 2
├───────┼───────┼────────────┼───────────────┤
│ Lamar │  4172 │         41 │             4 │
│ Josh  │  3731 │         28 │             6 │
└───────┴───────┴────────────┴───────────────┘

Table.reverse(table)

Reverse the rows in table.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
}

reverse(cities)
┌─────────────┬───────┐
│ city        │ state │ x 4
├─────────────┼───────┤
│ Houston     │ TX    │
│ Chicago     │ IL    │
│ Los Angeles │ CA    │
│ New York    │ NY    │
└─────────────┴───────┘

(Accessible as a global through Overloads.reverse)


Table.round(table)

(Accessible as a global through Overloads.round)


Table.roundTo(table, decimals)

(Accessible as a global through Overloads.roundTo)


Table.rows(table)

Get a list of the rows in table.

players = #{
  name    , yards , tds, ints
  "Lamar" ,  4172 ,  41,    4
  "Josh"  ,  3731 ,  28,    6
}

Table.rows(players)
[
  { name: "Lamar", yards: 4172, tds: 41, ints: 4 },
  { name: "Josh", yards: 3731, tds: 28, ints: 6 },
]

Table.select(table, columns)

Create a table containing the specified columns from table, in the given order. columns may be a single string (for one column) or a list of strings (for multiple columns).

players = #{
  name    , yards , tds, ints
  "Lamar" ,  4172 ,  41,    4
  "Josh"  ,  3731 ,  28,    6
}

select(players, ["yards", "name"])
select(players, "name")
┌───────┬───────┐
│ yards │ name  │ x 2
├───────┼───────┤
│  4172 │ Lamar │
│  3731 │ Josh  │
└───────┴───────┘
┌───────┐
│ name  │ x 2
├───────┤
│ Lamar │
│ Josh  │
└───────┘

(Accessible as a global through Overloads.select)


Table.set(table, selector, value)

Update the row or column in table that corresponds to selector with value. selector may be a number, string, or object.

  • If selector is a number, replace the row at index selector with the data in value, where value is an object whose keys match the columns of table.

  • If selector is a string, replace the column named selector with value.

    • If value is a list, it becomes the column data. A list value must have the same length as table.
    • If value is not a list, it is repeated across all rows.
  • If selector is an object, find the first row that matches matches selector, with the requirement that at least one row matches. Replace this row with the data in value, where value is an object whose keys match the columns of table.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
}

Table.set(cities, 0, { city: "Big Apple", state: "Empire" })
Table.set(cities, "state", ["New York", "Cali", "Illinois", "Texas"])
Table.set(cities, "state", "TX")
Table.set(cities, { state: "TX" },  { city: "Austin" })
Table.set(cities, { state: "TX" },  { city: "Phoenix", state: "AZ" })
┌─────────────┬────────┐
│ city        │ state  │ x 4
├─────────────┼────────┤
│ Big Apple   │ Empire │
│ Los Angeles │ CA     │
│ Chicago     │ IL     │
│ Houston     │ TX     │
└─────────────┴────────┘
┌─────────────┬──────────┐
│ city        │ state    │ x 4
├─────────────┼──────────┤
│ New York    │ New York │
│ Los Angeles │ Cali     │
│ Chicago     │ Illinois │
│ Houston     │ Texas    │
└─────────────┴──────────┘
┌─────────────┬───────┐
│ city        │ state │ x 4
├─────────────┼───────┤
│ New York    │ TX    │
│ Los Angeles │ TX    │
│ Chicago     │ TX    │
│ Houston     │ TX    │
└─────────────┴───────┘
┌─────────────┬───────┐
│ city        │ state │ x 4
├─────────────┼───────┤
│ New York    │ NY    │
│ Los Angeles │ CA    │
│ Chicago     │ IL    │
│ Austin      │ TX    │
└─────────────┴───────┘
┌─────────────┬───────┐
│ city        │ state │ x 4
├─────────────┼───────┤
│ New York    │ NY    │
│ Los Angeles │ CA    │
│ Chicago     │ IL    │
│ Phoenix     │ AZ    │
└─────────────┴───────┘

Note that if you want to update an existing variable, you could also use variable assignment.

citiesCopy = cities
citiesCopy[0] = { city: "Big Apple", state: "Empire" }
citiesCopy =
┌─────────────┬────────┐ │ city │ state │ x 4 ├─────────────┼────────┤ │ Big Apple │ Empire │ │ Los Angeles │ CA │ │ Chicago │ IL │ │ Houston │ TX │ └─────────────┴────────┘
citiesCopy = cities
citiesCopy.state = ["New York", "Cali", "Illinois", "Texas"]
citiesCopy =
┌─────────────┬──────────┐ │ city │ state │ x 4 ├─────────────┼──────────┤ │ New York │ New York │ │ Los Angeles │ Cali │ │ Chicago │ Illinois │ │ Houston │ Texas │ └─────────────┴──────────┘
citiesCopy = cities
citiesCopy.state = "TX"
citiesCopy =
┌─────────────┬───────┐ │ city │ state │ x 4 ├─────────────┼───────┤ │ New York │ TX │ │ Los Angeles │ TX │ │ Chicago │ TX │ │ Houston │ TX │ └─────────────┴───────┘
citiesCopy = cities
citiesCopy[{ state: "TX" }].city = "Austin"
citiesCopy =
┌─────────────┬───────┐ │ city │ state │ x 4 ├─────────────┼───────┤ │ New York │ NY │ │ Los Angeles │ CA │ │ Chicago │ IL │ │ Austin │ TX │ └─────────────┴───────┘
citiesCopy = cities
citiesCopy[{ state: "TX" }] = { city: "Phoenix", state: "AZ" }
citiesCopy =
┌─────────────┬───────┐ │ city │ state │ x 4 ├─────────────┼───────┤ │ New York │ NY │ │ Los Angeles │ CA │ │ Chicago │ IL │ │ Phoenix │ AZ │ └─────────────┴───────┘

Table.sortBy(table, columns)

Sort the rows of table in ascending order by one or more columns. columns may be a single string (for one column) or a list of strings (for multiple columns).

If multiple columns are given, rows are first sorted by the first column; if two rows have the same value in that column, the second column is used to break ties, and so on for any additional columns.

Values in the sort columns must be numbers, strings, booleans, or none, and all non-none values within a column must share the same type. Rows with none values in their sort columns will be placed at the end of the resulting table, whether sorting in ascending or descending order.

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
  "DC"           , none  ,     702250
}

sortBy(cities, "population")
sortBy(cities, ["state", "city"])
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 7
├──────────────┼───────┼────────────┤
│ DC           │       │     702250 │
│ Dallas       │ TX    │    1326087 │
│ San Diego    │ CA    │    1404452 │
│ San Antonio  │ TX    │    1526656 │
│ Philadelphia │ PA    │    1573916 │
│ Phoenix      │ AZ    │    1673164 │
│ Houston      │ TX    │    2390125 │
└──────────────┴───────┴────────────┘
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 7
├──────────────┼───────┼────────────┤
│ Phoenix      │ AZ    │    1673164 │
│ San Diego    │ CA    │    1404452 │
│ Philadelphia │ PA    │    1573916 │
│ Dallas       │ TX    │    1326087 │
│ Houston      │ TX    │    2390125 │
│ San Antonio  │ TX    │    1526656 │
│ DC           │       │     702250 │
└──────────────┴───────┴────────────┘

(Accessible as a global through Overloads.sortBy)


Table.sortDescBy(table, columns)

Sort the rows of table in descending order by one or more columns. See the docs for Table.sortBy for details on the sorting process.

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
  "DC"           , none  ,     702250
}

sortDescBy(cities, "population")
sortDescBy(cities, ["state", "city"])
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 7
├──────────────┼───────┼────────────┤
│ Houston      │ TX    │    2390125 │
│ Phoenix      │ AZ    │    1673164 │
│ Philadelphia │ PA    │    1573916 │
│ San Antonio  │ TX    │    1526656 │
│ San Diego    │ CA    │    1404452 │
│ Dallas       │ TX    │    1326087 │
│ DC           │       │     702250 │
└──────────────┴───────┴────────────┘
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 7
├──────────────┼───────┼────────────┤
│ San Antonio  │ TX    │    1526656 │
│ Houston      │ TX    │    2390125 │
│ Dallas       │ TX    │    1326087 │
│ Philadelphia │ PA    │    1573916 │
│ San Diego    │ CA    │    1404452 │
│ Phoenix      │ AZ    │    1673164 │
│ DC           │       │     702250 │
└──────────────┴───────┴────────────┘

(Accessible as a global through Overloads.sortDescBy)


Table.splice(table, index, count, rows)

Remove count rows from table starting at index, and replace them with those in the table rows.

cities = #{
  city           , state
  "New York"     , "NY"
  "Philadelphia" , "PA"
  "San Antonio"  , "TX"
  "Houston"      , "TX"
  "Phoenix"      , "AZ"
}

newRows = #{
  city          , state
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
}

Table.splice(cities, 1, 2, newRows)
┌─────────────┬───────┐
│ city        │ state │ x 5
├─────────────┼───────┤
│ New York    │ NY    │
│ Los Angeles │ CA    │
│ Chicago     │ IL    │
│ Houston     │ TX    │
│ Phoenix     │ AZ    │
└─────────────┴───────┘

Table.sum(table)

cities = #{
  city           , state , population , area
  "Houston"      , "TX"  ,    2390125 ,  640
  "Phoenix"      , "AZ"  ,    1673164 ,  518
  "Philadelphia" , "PA"  ,    1573916 ,  134
  "San Antonio"  , "TX"  ,    1526656 ,  499
  "San Diego"    , "CA"  ,    1404452 ,  326
  "Dallas"       , "TX"  ,    1326087 ,  340
}

sum(cities)
{ population: 9894400, area: 2457 }
Table.summarize(cities, "state", sum)
┌───────┬────────────┬──────┐
│ state │ population │ area │ x 4
├───────┼────────────┼──────┤
│ TX    │    5242868 │ 1479 │
│ AZ    │    1673164 │  518 │
│ PA    │    1573916 │  134 │
│ CA    │    1404452 │  326 │
└───────┴────────────┴──────┘

(Accessible as a global through Overloads.sum)


Table.summarize(table, columns, reducer)

Group the rows in table by one or more columns and summarize each group using the function reducer. columns may be a string (single column) or a list of strings (multiple columns).

Rows are grouped based on the values in the given columns (see the docs for Table.group for details on the grouping process.) reducer is called for each group and returns an object containing summary information. These objects are merged with each group's column values to form the final summary row for that group.

cities = #{
  city           , state , population
  "New York"     , "NY"  ,    8478072
  "Los Angeles"  , "CA"  ,    3878704
  "Chicago"      , "IL"  ,    2721308
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
}

fn calcStateStats(group)
  totalPop = sum(group.population)
  biggestCity = Table.maxBy(group, "population").city
  numCities = len(group)
  { totalPop, biggestCity, numCities }
end

Table.summarize(cities, "state", calcStateStats)
┌───────┬──────────┬──────────────┬───────────┐
│ state │ totalPop │ biggestCity  │ numCities │ x 6
├───────┼──────────┼──────────────┼───────────┤
│ NY    │  8478072 │ New York     │         1 │
│ CA    │  5283156 │ Los Angeles  │         2 │
│ IL    │  2721308 │ Chicago      │         1 │
│ TX    │  5242868 │ Houston      │         3 │
│ AZ    │  1673164 │ Phoenix      │         1 │
│ PA    │  1573916 │ Philadelphia │         1 │
└───────┴──────────┴──────────────┴───────────┘

Table.take(table, count)

Get the first count rows from table.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
  "Phoenix"     , "AZ"
}

take(cities, 3)
┌─────────────┬───────┐
│ city        │ state │ x 3
├─────────────┼───────┤
│ New York    │ NY    │
│ Los Angeles │ CA    │
│ Chicago     │ IL    │
└─────────────┴───────┘

(Accessible as a global through Overloads.take)


Table.takeLast(table, count)

Get the last count rows from table.

cities = #{
  city          , state
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "Houston"     , "TX"
  "Phoenix"     , "AZ"
}

Table.takeLast(cities, 3)
┌─────────┬───────┐
│ city    │ state │ x 3
├─────────┼───────┤
│ Chicago │ IL    │
│ Houston │ TX    │
│ Phoenix │ AZ    │
└─────────┴───────┘

Table.top(table, columns, count)

Sort table in descending order by columns and take the first count rows of the sorted table.

Equivalent to take(sortDescBy(table, columns), count).

cities = #{
  city           , state , population
  "Houston"      , "TX"  ,    2390125
  "Phoenix"      , "AZ"  ,    1673164
  "Philadelphia" , "PA"  ,    1573916
  "San Antonio"  , "TX"  ,    1526656
  "San Diego"    , "CA"  ,    1404452
  "Dallas"       , "TX"  ,    1326087
}

Table.top(cities, "population", 4)
┌──────────────┬───────┬────────────┐
│ city         │ state │ population │ x 4
├──────────────┼───────┼────────────┤
│ Houston      │ TX    │    2390125 │
│ Phoenix      │ AZ    │    1673164 │
│ Philadelphia │ PA    │    1573916 │
│ San Antonio  │ TX    │    1526656 │
└──────────────┴───────┴────────────┘

Table.unique(table)

Deduplicate rows of table, keeping only the first occurrence of each row.

cities = #{
  city          , state
  "New York"    , "NY"
  "New York"    , "NY"
  "Los Angeles" , "CA"
  "Chicago"     , "IL"
  "New York"    , "NY"
  "Houston"     , "TX"
  "Houston"     , "TX"
}

Table.unique(cities)
┌─────────────┬───────┐
│ city        │ state │ x 4
├─────────────┼───────┤
│ New York    │ NY    │
│ Los Angeles │ CA    │
│ Chicago     │ IL    │
│ Houston     │ TX    │
└─────────────┴───────┘