diff --git a/src/ISA/ISA/ArcTypes/ArcTable.fs b/src/ISA/ISA/ArcTypes/ArcTable.fs index 01906955..6f21091c 100644 --- a/src/ISA/ISA/ArcTypes/ArcTable.fs +++ b/src/ISA/ISA/ArcTypes/ArcTable.fs @@ -32,11 +32,11 @@ type ArcTable = Values = System.Collections.Generic.Dictionary() } - static member initWithHeaders(name,headers : ResizeArray) = + static member createFromHeaders(name,headers : ResizeArray) = ArcTable.create(name,headers,Dictionary()) static member createFromRows(name,headers : ResizeArray,rows : CompositeCell[][]) : ArcTable = - let t = ArcTable.initWithHeaders(name,headers) + let t = ArcTable.createFromHeaders(name,headers) t.AddRows(rows) t @@ -147,6 +147,7 @@ type ArcTable = newTable // - Column API - // + /// Replaces the header and cells of a column at given index. member this.UpdateColumn (columnIndex:int, header: CompositeHeader, ?cells: CompositeCell []) = SanityChecks.validateColumnIndex columnIndex this.ColumnCount false let column = CompositeColumn.create(header, ?cells=cells) @@ -164,20 +165,21 @@ type ArcTable = column.Cells |> Array.iteri (fun rowIndex v -> Unchecked.setCellAt(columnIndex,rowIndex,v) this.Values) Unchecked.fillMissingCells this.Headers this.Values - static member updatedColumn (columnIndex:int, header: CompositeHeader, ?cells: CompositeCell []) = + /// Replaces the header and cells of a column at given index. + static member updateColumn (columnIndex:int, header: CompositeHeader, ?cells: CompositeCell []) = fun (table:ArcTable) -> let newTable = table.Copy() newTable.UpdateColumn(columnIndex, header, ?cells=cells) newTable // - Column API - // - member this.InsertColumn (header:CompositeHeader, index: int, ?cells: CompositeCell []) = + member this.InsertColumn (index: int, header:CompositeHeader, ?cells: CompositeCell []) = this.AddColumn(header, index = index,?cells = cells, forceReplace = false) - static member insertColumn (header:CompositeHeader, index: int, ?cells: CompositeCell []) = + static member insertColumn (index: int, header:CompositeHeader, ?cells: CompositeCell []) = fun (table: ArcTable) -> let newTable = table.Copy() - newTable.InsertColumn(header, index, ?cells = cells) + newTable.InsertColumn(index, header, ?cells = cells) newTable // - Column API - // @@ -261,6 +263,10 @@ type ArcTable = let index = this.Headers |> Seq.findIndex (fun x -> x = header) this.GetColumn(index) + static member getColumnByHeader (header:CompositeHeader) = + fun (table:ArcTable) -> + table.GetColumnByHeader(header) + // - Row API - // member this.AddRow (?cells: CompositeCell [], ?index: int) : unit = let index = defaultArg index this.RowCount @@ -543,18 +549,7 @@ type ArcTable = |> fun rows -> ProcessParsing.alignByHeaders true rows |> fun (headers, rows) -> ArcTable.create(name,headers,rows) - /// This method is meant to update an ArcTable stored as a protocol in a study or investigation file with the information from an ArcTable actually stored as an annotation table - member this.UpdateReferenceByAnnotationTable(table:ArcTable) = - let nonProtocolColumns = - this.Headers - |> Seq.indexed - |> Seq.choose (fun (i,h) -> if h.isProtocolColumn then None else Some i) - |> Seq.toArray - this.RemoveColumns nonProtocolColumns - ArcTableAux.Unchecked.extendToRowCount table.RowCount this.Headers this.Values - for c in table.Columns do - this.AddColumn(c.Header, cells = c.Cells,forceReplace = true) - + /// Splits the table rowWise into a collection of tables, so that each new table has only one value for the given column static member SplitByColumnValues(columnIndex) = fun (table : ArcTable) -> let column = table.GetColumn(columnIndex) @@ -568,6 +563,7 @@ type ArcTable = ArcTable.createFromRows(table.Name,headers,rows) ) + /// Splits the table rowWise into a collection of tables, so that each new table has only one value for the given column static member SplitByColumnValuesByHeader(header : CompositeHeader) = fun (table : ArcTable) -> let index = table.Headers |> Seq.tryFindIndex (fun x -> x = header) @@ -575,11 +571,27 @@ type ArcTable = | Some i -> ArcTable.SplitByColumnValues i table | None -> [|table.Copy()|] + /// Splits the table rowWise into a collection of tables, so that each new table has only one value for the ProtocolREF column static member SplitByProtocolREF = fun (table : ArcTable) -> ArcTable.SplitByColumnValuesByHeader CompositeHeader.ProtocolREF table + /// This method is meant to update an ArcTable stored as a protocol in a study or investigation file with the information from an ArcTable actually stored as an annotation table + static member updateReferenceByAnnotationTable (refTable:ArcTable) (annotationTable:ArcTable) = + let refTable = refTable.Copy() + let annotationTable = annotationTable.Copy() + let nonProtocolColumns = + refTable.Headers + |> Seq.indexed + |> Seq.choose (fun (i,h) -> if h.isProtocolColumn then None else Some i) + |> Seq.toArray + refTable.RemoveColumns nonProtocolColumns + ArcTableAux.Unchecked.extendToRowCount annotationTable.RowCount refTable.Headers refTable.Values + for c in annotationTable.Columns do + refTable.AddColumn(c.Header, cells = c.Cells,forceReplace = true) + refTable + /// Append the rows of another table to this one /// /// The headers of the other table will be aligned with the headers of this table diff --git a/src/ISA/ISA/ArcTypes/ArcTables.fs b/src/ISA/ISA/ArcTypes/ArcTables.fs index cba453d9..c071fbbd 100644 --- a/src/ISA/ISA/ArcTypes/ArcTables.fs +++ b/src/ISA/ISA/ArcTypes/ArcTables.fs @@ -331,9 +331,8 @@ type ArcTables(thisTables:ResizeArray) = match Map.tryFind k referenceTableMap with | Some rt -> usedTables.Add(k) |> ignore - let rt = rt.Copy() - rt.UpdateReferenceByAnnotationTable t - ArcTable.create(t.Name, rt.Headers, rt.Values) + let updatedTable = ArcTable.updateReferenceByAnnotationTable rt t + ArcTable.create(t.Name, updatedTable.Headers, updatedTable.Values) | None -> t ) |> Array.groupBy (fun t -> t.Name) diff --git a/src/ISA/ISA/Update.fs b/src/ISA/ISA/Update.fs index b1147191..593e87f0 100644 --- a/src/ISA/ISA/Update.fs +++ b/src/ISA/ISA/Update.fs @@ -1,6 +1,6 @@ namespace ARCtrl.ISA.Aux -module List = +module internal List = let tryPickAndRemove (f : 'T -> 'U option) (lst : 'T list) = let rec loop newList remainingList = diff --git a/tests/ISA/ISA.Tests/ArcTable.Tests.fs b/tests/ISA/ISA.Tests/ArcTable.Tests.fs index f0e1ce62..272febe8 100644 --- a/tests/ISA/ISA.Tests/ArcTable.Tests.fs +++ b/tests/ISA/ISA.Tests/ArcTable.Tests.fs @@ -1964,7 +1964,7 @@ let private tests_UpdateRefWithSheet = valueTable.AddColumns(columns) let expectedRowCount = valueTable.RowCount let expectedColumnCount = 5 - refTable.UpdateReferenceByAnnotationTable valueTable + let refTable = ArcTable.updateReferenceByAnnotationTable refTable valueTable Expect.equal valueTable.ColumnCount 3 "ColumnCount of value table should not change after update" @@ -1997,7 +1997,7 @@ let private tests_UpdateRefWithSheet = valueTable.AddProtocolDescriptionColumn (Array.create 5 newProtocolDescription) let expectedRowCount = valueTable.RowCount let expectedColumnCount = 5 - refTable.UpdateReferenceByAnnotationTable valueTable + let refTable = ArcTable.updateReferenceByAnnotationTable refTable valueTable Expect.equal valueTable.ColumnCount 4 "ColumnCount of value table should not change after update" @@ -2029,7 +2029,7 @@ let private tests_UpdateRefWithSheet = valueTable.AddColumns(columns) let expectedRowCount = valueTable.RowCount let expectedColumnCount = 5 - refTable.UpdateReferenceByAnnotationTable valueTable + let refTable = ArcTable.updateReferenceByAnnotationTable refTable valueTable Expect.equal refTable.RowCount expectedRowCount "RowCount of reference table should be the same as value table after update" Expect.equal refTable.ColumnCount expectedColumnCount "ColumnCount of reference table should be the sum of value table and protocol table after update minus the param columns"