@std/table

⚠️ Deprecated: @std/table is deprecated. Use the built-in table type instead:

// Before (deprecated)
let table = import @std/table
let t = table.table(data)

// After (recommended)
let t = data.parseCSV()           // CSV string → table
let t = CSV(@./data.csv) <==      // CSV file → table
// Or work directly with arrays of dictionaries
let data = [{name: "Alice"}, {name: "Bob"}]
data.map(fn(row) { row.name })

Tables are now a built-in type. See Tables for the current API.

SQL-like data manipulation for arrays of dictionaries. Tables are immutable — all operations return new tables.

let table = import @std/table

Constructors

Function Args Description
table(arr) array of dictionaries Create a table from an array
table.fromDict(dict, keyCol?, valCol?) dictionary, string?, string? Create a table from dictionary entries
let data = [
    {name: "Alice", age: 30, dept: "Eng"},
    {name: "Bob", age: 25, dept: "Sales"},
    {name: "Carol", age: 35, dept: "Eng"}
]

let t = table.table(data)
t.count()                        // 3

// From dictionary — each key-value pair becomes a row
let counts = {a: 1, b: 2, c: 3}
let t2 = table.table.fromDict(counts, "letter", "count")
// [{letter: "a", count: 1}, {letter: "b", count: 2}, {letter: "c", count: 3}]

Query Methods

All query methods return a new Table, so they can be chained.

Method Args Returns Description
.where(fn) function Table Filter rows matching predicate
.orderBy(col, dir?) string, "asc" or "desc"? Table Sort by column (default: "asc")
.select(cols) array of strings Table Select specific columns
.limit(n) integer Table Take first n rows
.offset(n) integer Table Skip first n rows
let engineers = t.where(fn(row) { row.dept == "Eng" })
engineers.count()                // 2

let sorted = t.orderBy("age", "asc")
sorted.column("name")[0]         // "Bob" (youngest first)

let subset = t.select(["name", "age"])
subset.columnCount()             // 2

let page = t.orderBy("name").offset(1).limit(1)
page.count()                     // 1

Chaining

let result = t
    .where(fn(row) { row.age > 25 })
    .orderBy("name", "asc")
    .select(["name", "dept"])
    .limit(5)

Aggregation Methods

Method Args Returns Description
.count() none integer Number of rows
.sum(col) string number Sum of column values
.avg(col) string number Average of column values
.min(col) string number Minimum column value
.max(col) string number Maximum column value
t.count()                        // 3
t.sum("age")                     // 90
t.avg("age")                     // 30
t.min("age")                     // 25
t.max("age")                     // 35

Access Methods

Method Args Returns Description
.rowCount() none integer Number of rows
.columnCount() none integer Number of columns
.column(name) string array Extract a column as an array of values
t.rowCount()                     // 3
t.columnCount()                  // 3
t.column("name")                 // ["Alice", "Bob", "Carol"]

Tables also support indexing and iteration:

t[0]                             // {name: "Alice", age: 30, dept: "Eng"}

for (row in t) {
    row.name + ": " + row.dept
}

Mutation Methods

All mutation methods return a new table (the original is unchanged).

Method Args Returns Description
.appendRow(row) dictionary Table Add row at end
.insertRowAt(index, row) integer, dictionary Table Insert row at position
.appendCol(name, values) string, array Table Add column at end
.insertColAfter(after, name, values) string, string, array Table Insert column after another
.insertColBefore(before, name, values) string, string, array Table Insert column before another
.renameCol(old, new) string, string Table Rename a column
.dropCol(name) string Table Remove a column
let t2 = t.appendRow({name: "Dave", age: 28, dept: "Eng"})
t2.count()                       // 4

let t3 = t.appendCol("active", [true, true, false])
t3.columnCount()                 // 4

let t4 = t.renameCol("dept", "department")
t4.column("department")          // ["Eng", "Sales", "Eng"]

let t5 = t.dropCol("dept")
t5.columnCount()                 // 2

Functional Methods

Method Args Returns Description
.map(fn) function Table Transform each row
.find(fn) function dictionary or null First row matching predicate
.any(fn) function boolean Any row matches?
.all(fn) function boolean All rows match?
.unique(col) string Table Unique rows by column
.groupBy(col) string dictionary Group rows by column value
let names = t.map(fn(row) { {name: row.name.toUpper()} })

let alice = t.find(fn(row) { row.name == "Alice" })
alice.age                        // 30

t.any(fn(row) { row.age > 30 })  // true
t.all(fn(row) { row.age > 20 })  // true

let byDept = t.groupBy("dept")
byDept.Eng.count()               // 2

Export Methods

Method Args Returns Description
.toCSV() none string CSV string with header row
.toJSON() none string JSON array of objects
.toMarkdown() none string Markdown table
.toHTML() none tag HTML <table> element
.toBox(opts?) dictionary? string ASCII box-drawing table
.toArray() none array Convert to array of dictionaries
t.toCSV()
// "age,dept,name\n30,Eng,Alice\n25,Sales,Bob\n35,Eng,Carol\n"

t.toMarkdown()
// "| age | dept | name |\n|---|---|---|\n| 30 | Eng | Alice |..."

t.toJSON()
// '[{"age":30,"dept":"Eng","name":"Alice"},...]'

Box Table

toBox() renders an ASCII table suitable for terminal output. Pass an options dictionary to customize:

t.toBox()
// ┌─────┬───────┬───────┐
// │ age │ dept  │ name  │
// ├─────┼───────┼───────┤
// │ 30  │ Eng   │ Alice │
// │ 25  │ Sales │ Bob   │
// │ 35  │ Eng   │ Carol │
// └─────┴───────┴───────┘

t.toBox({title: "Team", style: "rounded"})

Validation Methods

Tables created from schemas support validation:

Method Args Returns Description
.as(schema) schema Table Attach a schema to the table
.validate() none ValidationResult Validate all rows against schema
.isValid() none boolean Are all rows valid?
.errors() none array Validation errors
.validRows() none Table Only valid rows
.invalidRows() none Table Only invalid rows
@schema User {
    name: string(required)
    age: integer
}

let t = table.table([
    {name: "Alice", age: 30},
    {name: "", age: 25},
    {name: "Carol", age: 35}
])

let typed = t.as(User)
typed.isValid()                  // false (empty name on row 2)
typed.validRows().count()        // 2
typed.invalidRows().count()      // 1

Key Differences from Other Languages

See Also