Dictionaries and tables: the column store
Amber's table is not a new primitive bolted on. It is two things you already have, a dictionary and a flip, composed. Understanding that is worth more than memorising the table functions.
A dictionary is two vectors
d: `a`b`c ! 1 2 3 / keys ! values
d`a / 1 -- index by key
d`a`c / 1 3
! d / `a`b`c -- the keys
. d / 1 2 3 -- the values
# d / 3A table is a flipped dictionary of columns
cd: `sym`px ! (`a`b`c; 10 20 30) / call it cd, NOT cols -- cols is a builtin
t: + cd / that flip IS the table
t / a 3-row table with columns sym and px
t: ([] sym: `a`b`c; px: 10 20 30) / the literal syntax for the same thingBecause the columns are the storage, a column is a plain vector and everything you learned in chapters 3 and 4 applies to it directly:
t: ([] sym: `a`b`c; px: 10 20 30)
t`px / 10 20 30 -- a column is just a vector
+/ t`px / 60
t`px / 10 20 30
# t / 3 -- rows
cols t / `sym`px
t 0 / a row, as a dictionary
This is why it is fast
Selecting a column is a pointer, not a copy or a gather. Summing one column of a fifty-column table touches only that column's memory. A row store has to walk past the other forty-nine.
Inspecting
t: ([] sym: `a`b`c; px: 10 20 30)
meta t / column names, types and attributes
show t / grid-print it
5 # t / first 5 rows -- take works on tables
cols t / column names
istable t / 1Keyed tables
A keyed table is a dictionary whose key and value are both tables. That is what select ... by returns, and what joins look up against:
kt: ([sym: `a`b`c] px: 10 20 30)
keys kt / the key column(s)
value kt / the value table
unkey kt / back to a flat table
xkey[`sym; t] / key an existing table by a columnRestructuring
t: ([] sym: `a`b`a`b; px: 10 20 30 40)
xgroup[`sym; t] / one row per sym, px becomes a nested column
ungroup xgroup[`sym; t] / and back again
xasc[`px; t] / sort the table by a column
xdesc[`px; t]
xcols[`px`sym; t] / reorder columns