Angara.Table


Table as Collection of Rows

We described that a table of Angara.Table is basically an immutable collection of named columns, Table as Collection of Columns. Still sometimes it is necessary to view it as a collection of rows.

In the examples here we will use the table containing the columns "x" and "sin(x)":

1: 
2: 
3: 
4: 
let table = 
    Table.OfColumns
        [ Column.Create ("x", [| for i in 0..99 -> float(i) / 10.0  |])
          Column.Create ("sin(x)", [| for i in 0..99 -> sin (float(i) / 10.0) |]) ]

A number of rows in the table is available through the property RowsCount:

1: 
printf "Rows count: %d" table.RowsCount
Rows count: 100

There are three ways to perform row-wise data access:

  • Get column values then do explicit slicing:
1: 
2: 
3: 
4: 
let rows : (float*float) seq = 
    let x = table.["x"].Rows.AsReal
    let sinx = table.["sin(x)"].Rows.AsReal
    seq{ for i in 0..table.RowsCount-1 -> x.[i], sinx.[i] }
seq
  [(0.0, 0.0); (0.1, 0.09983341665); (0.2, 0.1986693308); (0.3, 0.2955202067);
   ...]
  • Use helper function Table.Map which invokes the given function for each of the table rows and provides values of certain columns as arguments (see Table Operations); the result is a sequence of values returned by the function calls:
1: 
2: 
let rows' : (float*float) seq =
    table |> Table.Map ["x";"sin(x)"] (fun (x:float) (sinx:float) -> x, sinx)
seq
  [(0.0, 0.0); (0.1, 0.09983341665); (0.2, 0.1986693308); (0.3, 0.2955202067);
   ...]
  • If table schema is known and a row can be represented as a record, you can use the generic function Table.ToRows<'r> which returns 'r seq, one instance of 'r for each of the rows. Note that the record may not have a property for each of the table columns.
1: 
2: 
type SinX = { x: float; ``sin(x)``: float }
let rows'' : SinX seq = table.ToRows<SinX>()
seq
  [{x = 0.0;
    sin(x) = 0.0;}; {x = 0.1;
                     sin(x) = 0.09983341665;}; {x = 0.2;
                                                sin(x) = 0.1986693308;};
   {x = 0.3;
    sin(x) = 0.2955202067;}; ...]

Typed Table

The typed table is a table that exposes its rows as a collection of typed instances. It is represented as a generic type Table<'r> inherited from Table.

The function Table.OfRows<'r> creates an instance of type Table<'r>, such that each public property of a given type 'r becomes the table column with the name and type identical to the property; each table row corresponds to an element of the input sequence with the order respected. If the type 'r is an F# record, the order of columns is identical to the record properties order. If there is a public property having a type that is not valid for a table column, the function fails with an exception.

1: 
let tableSinX : Table<SinX> = Table.OfRows rows''
seq
  [x[100]: Array is not evaluated yet; sin(x)[100]: Array is not evaluated yet]

The Table<'r> exposes the Rows property which returns table rows as ImmutableArray<'r>:

1: 
let sinRow : SinX = tableSinX.Rows.[0]
{x = 0.0;
 sin(x) = 0.0;}

The type Table<'r> allows efficiently appending a table with new rows:

1: 
2: 
let tableSinX' = 
    tableSinX.AddRows (seq{ for i in 100..199 -> let x = float(i)/10.0 in { x = x; ``sin(x)`` = sin x } })
seq
  [x[200]: Array is not evaluated yet; sin(x)[200]: Array is not evaluated yet]
Fork me on GitHub