Last active
November 25, 2021 21:39
-
-
Save tomaspavlic/a5622a8077ff23d7ec1d6e2aac8e6597 to your computer and use it in GitHub Desktop.
F# table
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
open System.Data | |
open System.Linq | |
type Table<'key> when 'key: comparison = | |
{ columns: string list | |
sortedKeys: 'key seq option | |
map: Map<'key, double array> } | |
module Table = | |
let addColumn column table items = | |
let map = | |
items | |
|> Seq.fold (fun map (key, value) -> | |
Map.change key (function | |
| None -> Array.singleton value |> Some | |
| Some v -> Array.singleton value |> Array.append v |> Some) map | |
) table.map | |
{ table with | |
columns = table.columns @ [ column ] | |
map = map } | |
let clear table = | |
let columnsLength = List.length table.columns | |
let map = Map.filter (fun _ list -> (Array.length list) = columnsLength) table.map | |
{ table with map = map } | |
let keys table = | |
table.map | |
|> Map.keys :> seq<_> | |
let column index table = | |
table.map | |
|> Seq.map (fun pair -> pair.Key, pair.Value.[index]) | |
let columnByName columnName table = | |
let colIndex = table.columns |> Seq.findIndex (fun c -> c = columnName) | |
column colIndex table | |
let copyColumn columnName newColumnName f table = | |
let column = columnByName columnName table | |
column | |
|> Seq.map (fun (key, value) -> key, f value) | |
|> addColumn newColumnName table | |
let withColumns columns = | |
{ columns = columns |> List.ofSeq | |
sortedKeys = None | |
map = Map.empty } | |
let sortBy (f: 'key -> 'a) (table: Table<'key>) = | |
let sortedKeys = keys table |> Seq.sortBy f | |
{ table with sortedKeys = Some sortedKeys} | |
let toDataTable keyName (table: Table<'key>) = | |
let dt = new DataTable() | |
dt.Columns.Add(keyName, typeof<'key>) |> ignore | |
table.columns |> Seq.map (fun c -> new DataColumn(c, typeof<double>)) |> Seq.iter dt.Columns.Add | |
table.sortedKeys | |
|> Option.defaultWith (fun () -> keys table) | |
|> Seq.iter (fun key -> | |
let row = dt.NewRow() | |
table.map.[key] |> Seq.iteri (fun ix v -> row.[ix + 1] <- v) | |
dt.Rows.Add(row) | |
) | |
dt | |
let empty = | |
{ columns = [] | |
sortedKeys = None | |
map = Map.empty } | |
let intersect table1 table2 f = | |
if table1.columns <> table2.columns then invalidOp "" | |
let intersectedSortedKeys = (keys table1).Intersect(keys table2) | |
let map = | |
intersectedSortedKeys | |
|> Seq.fold (fun map key -> | |
let arr = Array.map2 f table1.map.[key] table2.map.[key] | |
Map.add key arr map | |
) Map.empty | |
{ columns = table1.columns | |
sortedKeys = None | |
map = map } | |
let add key column value table = | |
let columnIndex = table.columns |> Seq.findIndex (fun c -> c = column) | |
let map = | |
Map.change key (fun v -> | |
let arr = v |> Option.defaultWith (fun () -> Array.create table.columns.Length Double.NaN) | |
arr.[columnIndex] <- value | |
arr |> Some) table.map | |
{ table with map = map } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment