Skip to content

Instantly share code, notes, and snippets.

@tomaspavlic
Last active November 25, 2021 21:39
Show Gist options
  • Save tomaspavlic/a5622a8077ff23d7ec1d6e2aac8e6597 to your computer and use it in GitHub Desktop.
Save tomaspavlic/a5622a8077ff23d7ec1d6e2aac8e6597 to your computer and use it in GitHub Desktop.
F# table
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