Introducing MatrixTable<'v>
This commit is contained in:
Родитель
4b60d3e36a
Коммит
7d44bc99a5
|
@ -60,6 +60,7 @@
|
|||
<Compile Include="CsvReadTests.fs" />
|
||||
<Compile Include="CsvWriteTests.fs" />
|
||||
<Compile Include="TableTests.fs" />
|
||||
<Compile Include="MatrixTableTests.fs" />
|
||||
<Compile Include="TableSerializerTests.fs" />
|
||||
<Compile Include="StatisticsTests.fs" />
|
||||
<Content Include="packages.config" />
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
module MatrixTableTests
|
||||
|
||||
open FsUnit
|
||||
open NUnit.Framework
|
||||
open FsCheck
|
||||
open Angara.Data.TestsF.Common
|
||||
open Angara.Data
|
||||
open System.IO
|
||||
open System.Collections.Immutable
|
||||
|
||||
[<Property(Verbose=false); Category("CI")>]
|
||||
let ``Creates a matrix table from rows matrix``(matrix:int[,]) =
|
||||
let n,m = matrix.GetLength(0), matrix.GetLength(1)
|
||||
let immMatrix =
|
||||
Seq.init n (fun irow -> ImmutableArray.Create<int>(matrix.[irow,*]))
|
||||
|> ImmutableArray.CreateRange
|
||||
let names = Seq.init m (fun i -> sprintf "column %d" i) |> ImmutableArray.CreateRange
|
||||
let t = Table.OfMatrix(names, immMatrix)
|
||||
|
||||
Assert.AreEqual(m, t.Count, "columns count")
|
||||
Assert.AreEqual(names, t |> Seq.map(fun c -> c.Name), "column names")
|
||||
for icol in 0 .. t.Count-1 do
|
||||
Assert.AreEqual(matrix.[*,icol] |> Array.toSeq, t.[icol].Rows.AsInt, sprintf "Column %d" icol)
|
||||
|
||||
Assert.AreEqual((if t.Count = 0 then 0 else n), t.RowsCount, "rows count")
|
||||
for irow in 0 .. t.RowsCount-1 do
|
||||
Assert.AreEqual(matrix.[irow,*] |> Array.toSeq, t.Matrix.[irow], sprintf "Row %d" irow)
|
||||
|
||||
|
||||
[<Test; Category("CI")>]
|
||||
let ``Adds a column and a row to a matrix table`` () =
|
||||
let matrix =
|
||||
ImmutableArray.Create<ImmutableArray<int>>
|
||||
[| ImmutableArray.Create<int> [|11;12;13|]
|
||||
ImmutableArray.Create<int> [|21;22;23|] |]
|
||||
|
||||
let t = Table.OfMatrix (ImmutableArray.CreateRange ["a"; "b"; "c"], matrix)
|
||||
let t2 = t.AddColumn("d", ImmutableArray.Create<int>([|14;24|]))
|
||||
.AddRow(ImmutableArray.Create<int>([|31;32;33;34|]))
|
||||
|
||||
Assert.AreEqual(4, t2.Count, "columns count")
|
||||
Assert.AreEqual(["a";"b";"c";"d"], t2 |> Seq.map(fun c -> c.Name), "column names")
|
||||
Assert.AreEqual([|11;12;13;14|] |> Array.toSeq, t2.Matrix.[0], "row 0")
|
||||
Assert.AreEqual([|21;22;23;24|] |> Array.toSeq, t2.Matrix.[1], "row 1")
|
||||
Assert.AreEqual([|31;32;33;34|] |> Array.toSeq, t2.Matrix.[2], "row 2")
|
||||
|
||||
Assert.AreEqual([|11;21;31|] |> Array.toSeq, t2.[0].Rows.AsInt, "column 0")
|
||||
Assert.AreEqual([|12;22;32|] |> Array.toSeq, t2.[1].Rows.AsInt, "column 1")
|
||||
Assert.AreEqual([|13;23;33|] |> Array.toSeq, t2.[2].Rows.AsInt, "column 2")
|
||||
Assert.AreEqual([|14;24;34|] |> Array.toSeq, t2.[3].Rows.AsInt, "column 3")
|
||||
|
|
@ -187,15 +187,13 @@ let sin_avg = table.["sin(x)"].Rows.AsReal |> Seq.average
|
|||
There are several ways how rows can be represented to construct a table. First is to use `Table.ofRecords` which builds a table
|
||||
from a sequence of record type instances, when one instance is one row and record field is a column: *)
|
||||
|
||||
//type Wheat = { lat: float; lon: float; wheat: float }
|
||||
//let records : Wheat[] = [| (* ... *) |]
|
||||
//
|
||||
//let tableWheat = Table.ofRecords records
|
||||
let records : Wheat[] = [| (* ... *) |]
|
||||
let tableWheat = Table.ofRows records
|
||||
|
||||
(** Appending a table with a row:
|
||||
*)
|
||||
|
||||
// tableWheat |> Table.AppendRow r
|
||||
tableWheat.AddRow row
|
||||
|
||||
(**
|
||||
Second way is to use `Table.ofTuples2`, `Table.ofTuples3` etc which builds a table from a sequence of tuples,
|
||||
|
@ -243,6 +241,32 @@ let rows' : (float*float) seq =
|
|||
|
||||
(**
|
||||
|
||||
### Table as Matrix
|
||||
|
||||
Matrix table is represented as `Angara.Data.MatrixTable<'v>` inherited from `Angara.Data.Table`, where
|
||||
type `'v` is a matrix value type, i.e. all columns of the table have same type which must be a valid column type.
|
||||
|
||||
To create a matrix table, use `Table.OfMatrix` and provide column names and the matrix as an array of rows:
|
||||
|
||||
*)
|
||||
|
||||
let matrix =
|
||||
ImmutableArray.Create(
|
||||
[| ImmutableArray.Create([|11;12;13|])
|
||||
ImmutableArray.Create([|21;22;23|]) |])
|
||||
|
||||
let tableMatrix = Table.OfMatrix (["a"; "b"], matrix)
|
||||
|
||||
(**
|
||||
Matrix table allows adding columns and rows using `AddRows`, `AddRow` and `AddColumns`, `AddColumn` functions:
|
||||
*)
|
||||
|
||||
tableMatrix
|
||||
.AddColumn("c", ImmutableArray.Create([|14;24;34|]))
|
||||
.AddRow(ImmutableArray.Create([|31;32;33;34|]))
|
||||
|
||||
(**
|
||||
|
||||
## Save and Load
|
||||
|
||||
The `Table` type exposes static functions `Save` and `Load` to save and load a table in the delimited text format
|
||||
|
|
|
@ -163,6 +163,8 @@ type Table internal (columns : Column list, height : int) =
|
|||
static member OfColumns (columns: Column seq) : Table = Table(columns)
|
||||
static member OfRows<'r> (rows : 'r seq) : Table<'r> = Table<'r>(rows |> ImmutableArray.CreateRange)
|
||||
static member OfRows<'r> (rows : ImmutableArray<'r>) : Table<'r> = Table<'r>(rows)
|
||||
static member OfMatrix<'v> (columnNames:ImmutableArray<string>, matrixRows : ImmutableArray<ImmutableArray<'v>>) : MatrixTable<'v> =
|
||||
MatrixTable<'v>(columnNames, matrixRows)
|
||||
|
||||
static member internal ColumnsOfRows<'r>(rows : ImmutableArray<'r>) : Column seq =
|
||||
let typeR = typeof<'r>
|
||||
|
@ -389,4 +391,45 @@ and Table<'r>(rows : ImmutableArray<'r>) =
|
|||
|
||||
member x.AddRows (r : 'r seq) : Table<'r> = Table<'r>(rows.AddRange r)
|
||||
member x.AddRow (r: 'r) : Table<'r> = Table<'r>(rows.Add r)
|
||||
|
||||
and MatrixTable<'v> private (columns: Column list, matrixRows : ImmutableArray<ImmutableArray<'v>>) =
|
||||
inherit Table(columns)
|
||||
|
||||
do
|
||||
if matrixRows.Length > 0 then
|
||||
let n = matrixRows.[0].Length
|
||||
if n <> columns.Length then invalidArg "columns" "Number of columns is different than given rows length"
|
||||
for i in 1 .. matrixRows.Length-1 do
|
||||
if matrixRows.[i].Length <> n then invalidArg "matrixRows" "There are rows of different length"
|
||||
|
||||
new(columnsNames: ImmutableArray<string>, matrixRows : ImmutableArray<ImmutableArray<'v>>) =
|
||||
MatrixTable<'v>(
|
||||
columnsOfMatrix (matrixRows, columnsNames.Length)
|
||||
|> Seq.mapi (fun i cv -> Column.OfLazyArray(columnsNames.[i], cv, matrixRows.Length)) |> Seq.toList,
|
||||
matrixRows)
|
||||
|
||||
member x.Matrix : ImmutableArray<ImmutableArray<'v>> = matrixRows
|
||||
|
||||
member x.AddColumns (columns : (string*ImmutableArray<'v>) seq) : MatrixTable<'v> =
|
||||
let columns = columns |> Seq.cache
|
||||
let cols = columns |> Seq.map snd |> Seq.toArray
|
||||
let n = cols.Length
|
||||
let m = x.Count
|
||||
let rows_bld = ImmutableArray.CreateBuilder<ImmutableArray<'v>>(matrixRows.Length)
|
||||
for irow in 0..matrixRows.Length-1 do
|
||||
let slice_bld = ImmutableArray.CreateBuilder<'v>(n + m)
|
||||
slice_bld.AddRange(matrixRows.[irow])
|
||||
for icol in 0..n-1 do slice_bld.Add(cols.[icol].[irow])
|
||||
rows_bld.Add (slice_bld.MoveToImmutable())
|
||||
let rows2 = rows_bld.MoveToImmutable()
|
||||
let columnsEx = columns |> Seq.map(fun (n,v) -> Column.OfArray(n,v)) |> Seq.toList
|
||||
let columns2 = List.append x.Columns columnsEx
|
||||
MatrixTable<'v>(columns2, rows2)
|
||||
|
||||
member x.AddColumn (name:string, values:ImmutableArray<'v>) = x.AddColumns([name,values])
|
||||
|
||||
member x.AddRows (rows : ImmutableArray<'v> seq) : MatrixTable<'v> =
|
||||
let rows2 = matrixRows.AddRange(rows)
|
||||
MatrixTable<'v>(ImmutableArray.CreateRange(x |> Seq.map(fun c -> c.Name)), rows2)
|
||||
|
||||
member x.AddRow (row : ImmutableArray<'v>) : MatrixTable<'v> = x.AddRows [row]
|
|
@ -54,6 +54,7 @@ type [<Class>] Column =
|
|||
/// Represents a table wich is an immutable list of named columns.
|
||||
/// The type is thread safe.
|
||||
type [<Class>] Table =
|
||||
new : columns : Column seq -> Table
|
||||
interface IEnumerable<Column>
|
||||
|
||||
/// Gets a count of the total number of columns in the table.
|
||||
|
@ -103,6 +104,8 @@ type [<Class>] Table =
|
|||
/// If there is a public property having a type that is not valid for a table column, the function fails with an exception.
|
||||
static member OfRows<'r> : ImmutableArray<'r> -> Table<'r>
|
||||
|
||||
static member OfMatrix<'v> : columnNames:ImmutableArray<string> * matrixRows:ImmutableArray<ImmutableArray<'v>> -> MatrixTable<'v>
|
||||
|
||||
/// Creates a new, empty table
|
||||
static member Empty : Table
|
||||
/// Creates a new table that has all columns of the original table appended with the given column.
|
||||
|
@ -234,4 +237,17 @@ and [<Class>] Table<'r> =
|
|||
new : rows:ImmutableArray<'r> -> Table<'r>
|
||||
member Rows : ImmutableArray<'r>
|
||||
member AddRows : 'r seq -> Table<'r>
|
||||
member AddRow : 'r -> Table<'r>
|
||||
member AddRow : 'r -> Table<'r>
|
||||
|
||||
and [<Class>] MatrixTable<'v> =
|
||||
inherit Table
|
||||
private new : columns:Column list * matrixRows : ImmutableArray<ImmutableArray<'v>> -> MatrixTable<'v>
|
||||
new : columnsNames:ImmutableArray<string> * matrixRows:ImmutableArray<ImmutableArray<'v>> -> MatrixTable<'v>
|
||||
|
||||
member Matrix : ImmutableArray<ImmutableArray<'v>>
|
||||
|
||||
member AddColumns : (string*ImmutableArray<'v>) seq -> MatrixTable<'v>
|
||||
member AddColumn : string*ImmutableArray<'v> -> MatrixTable<'v>
|
||||
|
||||
member AddRows : ImmutableArray<'v> seq -> MatrixTable<'v>
|
||||
member AddRow : ImmutableArray<'v> -> MatrixTable<'v>
|
|
@ -51,4 +51,15 @@ let arrayOfProp<'r,'p> (rows: ImmutableArray<'r>, p:System.Reflection.PropertyIn
|
|||
let inline immToArray (imm: ImmutableArray<'a>) =
|
||||
let arr = Array.zeroCreate imm.Length
|
||||
imm.CopyTo(arr)
|
||||
arr
|
||||
arr
|
||||
|
||||
let columnsOfMatrix (matrixRows : ImmutableArray<ImmutableArray<'v>>, colN: int) =
|
||||
let rowsCount = matrixRows.Length
|
||||
Seq.init colN (fun colInd ->
|
||||
lazy(
|
||||
let bld = ImmutableArray.CreateBuilder<'v>(rowsCount)
|
||||
bld.Count <- rowsCount
|
||||
for rowInd in 0..rowsCount-1 do
|
||||
bld.[rowInd] <- matrixRows.[rowInd].[colInd]
|
||||
bld.MoveToImmutable()
|
||||
))
|
Загрузка…
Ссылка в новой задаче