Table
A table is a set of records, where each record corresponds to a row and each column has a name and kind. Tables provide structured, columnar data that is flexible and human-readable.
Syntax
Basic Syntax
Tables are defined using the pipe | character. Each column is defined with a name and a kind, which describes the type of data it holds.
| x<f32> y<bool> | | 1.2 true | | 1.3 false |
This creates a table with two columns, x of kind f32 and y of kind bool:
x<f32> y<bool> 1.2 true 1.3 false
Inline Syntax
You can write tables inline as well:
| x<f32> y<bool> | 1.2 true | 1.3 false |
Fancy Syntax
The Mech REPL formats matrix output using fancy box drawing characters for better readability.
╭────────┬─────────╮ │ x<f32> │ y<bool> │ ├────────┼─────────┤ │ 1.2 │ true │ │ 1.3 │ false │ ╰────────┴─────────╯
Mech can parse data formatted this way, allowing you to copy or pipe REPL output directly into a Mech program that expects a table. The above example evaluates to:
x<u64> y<bool> 1.2 true 1.3 false
Fancy tables can be formatted in a variety of ways:
╭────────┬────────╮ │ x<u64> │ y<f32> │ ├────────┼────────┤ │ 1 │ 2 │ ├────────┼────────┤ │ 3 │ 4 │ ╰────────┴────────╯
This one has no horizontal lines between rows, making it more compact:
╭────────┬────────╮ │ x<u64> │ y<f32> │ │ 1 │ 2 │ │ 3 │ 4 │ ╰────────┴────────╯
Kind
A table's kind describes the names and kinds of the columns, as well as the number of rows in the table. For example:
<|x<u8>,y<f32>|:3>This represents a table with two columns, x of kind u8 and y of kind f32, and 3 rows.
Construction
Tables can be constructed of vectors, matrices, or records.
From vectors
From a matrix
You can create a table from a matrix using a kind annotation, as long as the kinds of the table columns are compatible with the matrix kind. For example, if you have a matrix of kind f64, you can create a table with columns of kind f64:
For example:
This creates a table a with two columns, foo and bar, both of kind f64, and two rows corresponding to the rows of the matrix x.
The matrix [a.foo a.bar] is identical to the original matrix x.
It's possible to convert a matrix of one kind to a table of different kinded columns, as long as the conversion is valid. For example, you can convert a matrix of f64 to a table with u8 columns:
From records
Accessing Elements
Consider the table:
a:=x<f64> | y<bool> |
|---|---|
| 1.6 | true |
| 1.3 | false |
| 2.7 | false |
| 1.5 | true |
Access a Column
Use dot indexing to access columns. For example a.x. The kind of the result is a column vector with elements of the column's kind. For instance, column x has kind f32, so the result of accessing that column is a column vector of kind [f32], with the same number of rows as the table:
Select column x, which has kind [f32]
Access an Element
You can access an individual element in a table column by specifying the row index on the selected column:
Select the first element of column x, which has kind f32
Table columns are just vectors, so they support the same indexing operations as vectors.
Access a Record
You can access a record in a table by specifying the row index on the table itself:
Select the first record in the table, returns a record
Access Several Records
You can access a range of records by using a vector as an index:
Select records 2 through 3, returns a table
It's possible to select the same row multiple times:
Select records 1 and 2 twice
Filter Records
You can filter records using logical indexing. For example, to select records where y is true:
Select records where y is true
Or to filter records where x is greater than 1.5:
Select records where x is greater than 1.5
Heterogeneous Columns
The kind * indicates that a column may contain heterogeneous data:
x<*> y<*> 1.2 true "Hi" 8
Each cell in the column may hold a different type of value.
Partial Columns
You can omit values in the table using using _ to indicate a missing value. In this case, the kind of the column must be annotated with an option kind, indicated by a ? suffix:
x<u8?> y<string?> z<[u8]:1,3?> _ "a" [1 2 3] 4 "b" _ 7 _ [7 8 9]