From 28841af9804243205a9693be0cb501ce2d980302 Mon Sep 17 00:00:00 2001 From: xuri Date: Fri, 1 Oct 2021 21:43:02 +0800 Subject: [PATCH] initialize formula function TRANSPOSE, ref #65 and remove unused exported error variable ErrToExcelTime --- calc.go | 33 +++++++++++++++++++++++++++++++++ calc_test.go | 17 +++++++++++++++++ errors.go | 4 +--- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/calc.go b/calc.go index 4303b433..1c6edca0 100644 --- a/calc.go +++ b/calc.go @@ -497,6 +497,7 @@ type formulaFuncs struct { // TAN // TANH // TODAY +// TRANSPOSE // TRIM // TRUE // TRUNC @@ -7794,6 +7795,38 @@ func (fn *formulaFuncs) MATCH(argsList *list.List) formulaArg { return calcMatch(matchType, formulaCriteriaParser(argsList.Front().Value.(formulaArg).String), lookupArray) } +// TRANSPOSE function 'transposes' an array of cells (i.e. the function copies +// a horizontal range of cells into a vertical range and vice versa). The +// syntax of the function is: +// +// TRANSPOSE(array) +// +func (fn *formulaFuncs) TRANSPOSE(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "TRANSPOSE requires 1 argument") + } + args := argsList.Back().Value.(formulaArg).ToList() + rmin, rmax := calcRowsMinMax(argsList) + cmin, cmax := calcColumnsMinMax(argsList) + cols, rows := cmax-cmin+1, rmax-rmin+1 + src := make([][]formulaArg, 0) + for i := 0; i < len(args); i += cols { + src = append(src, args[i:i+cols]) + } + mtx := make([][]formulaArg, cols) + for r, row := range src { + colIdx := r % rows + for c, cell := range row { + rowIdx := c % cols + if len(mtx[rowIdx]) == 0 { + mtx[rowIdx] = make([]formulaArg, rows) + } + mtx[rowIdx][colIdx] = cell + } + } + return newMatrixFormulaArg(mtx) +} + // VLOOKUP function 'looks up' a given value in the left-hand column of a // data array (or table), and returns the corresponding value from another // column of the array. The syntax of the function is: diff --git a/calc_test.go b/calc_test.go index 54629a6e..a391a195 100644 --- a/calc_test.go +++ b/calc_test.go @@ -2217,6 +2217,8 @@ func TestCalcCellValue(t *testing.T) { "=MATCH(0,A1:A1,\"x\")": "MATCH requires numeric match_type argument", "=MATCH(0,A1)": "MATCH arguments lookup_array should be one-dimensional array", "=MATCH(0,A1:B1)": "MATCH arguments lookup_array should be one-dimensional array", + // TRANSPOSE + "=TRANSPOSE()": "TRANSPOSE requires 1 argument", // VLOOKUP "=VLOOKUP()": "VLOOKUP requires at least 3 arguments", "=VLOOKUP(D2,D1,1,FALSE)": "VLOOKUP requires second argument of table array", @@ -2611,6 +2613,21 @@ func TestCalcMatchPattern(t *testing.T) { assert.False(t, matchPattern("file/?", "file/abc/bcd/def")) } +func TestCalcTRANSPOSE(t *testing.T) { + cellData := [][]interface{}{ + {"a", "d"}, + {"b", "e"}, + {"c", "f"}, + } + formula := "=TRANSPOSE(A1:A3)" + f := prepareCalcData(cellData) + formulaType, ref := STCellFormulaTypeArray, "D1:F2" + assert.NoError(t, f.SetCellFormula("Sheet1", "D1", formula, + FormulaOpts{Ref: &ref, Type: &formulaType})) + _, err := f.CalcCellValue("Sheet1", "D1") + assert.NoError(t, err, formula) +} + func TestCalcVLOOKUP(t *testing.T) { cellData := [][]interface{}{ {nil, nil, nil, nil, nil, nil}, diff --git a/errors.go b/errors.go index e89fea1b..56a2280d 100644 --- a/errors.go +++ b/errors.go @@ -79,8 +79,6 @@ var ( // ErrAddVBAProject defined the error message on add the VBA project in // the workbook. ErrAddVBAProject = errors.New("unsupported VBA project extension") - // ErrToExcelTime defined the error message on receive a not UTC time. - ErrToExcelTime = errors.New("only UTC time expected") // ErrMaxRows defined the error message on receive a row number exceeds maximum limit. ErrMaxRows = errors.New("row number exceeds maximum limit") // ErrMaxRowHeight defined the error message on receive an invalid row @@ -112,7 +110,7 @@ var ( // ErrDefinedNameduplicate defined the error message on the same name // already exists on the scope. ErrDefinedNameduplicate = errors.New("the same name already exists on the scope") - // ErrCustomNumFmt defined the error message on receive the empty parameter. + // ErrCustomNumFmt defined the error message on receive the empty custom number format. ErrCustomNumFmt = errors.New("custom number format can not be empty") // ErrFontLength defined the error message on the length of the font // family name overflow.