summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2021-02-09 00:12:53 +0800
committerxuri <xuri.me@gmail.com>2021-02-09 00:12:53 +0800
commit23c73ab527731f9d414e81f7ea15e2ae1a72a290 (patch)
tree82a213f884c2b0bbc8458843d9f6fb84d5fff38f
parent30549c5e90884789fff6599d6e773d1ca56ba962 (diff)
init new formula function: HLOOKUP
-rw-r--r--calc.go62
-rw-r--r--calc_test.go25
2 files changed, 83 insertions, 4 deletions
diff --git a/calc.go b/calc.go
index 1d10f62..df2230e 100644
--- a/calc.go
+++ b/calc.go
@@ -2214,11 +2214,12 @@ func (fn *formulaFuncs) MDETERM(argsList *list.List) (result formulaArg) {
num float64
numMtx = [][]float64{}
err error
- strMtx = argsList.Front().Value.(formulaArg).Matrix
+ strMtx [][]formulaArg
)
if argsList.Len() < 1 {
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "MDETERM requires at least 1 argument")
}
+ strMtx = argsList.Front().Value.(formulaArg).Matrix
var rows = len(strMtx)
for _, row := range argsList.Front().Value.(formulaArg).Matrix {
if len(row) != rows {
@@ -3705,6 +3706,63 @@ func compareFormulaArgMatrix(lhs, rhs formulaArg, caseSensitive, exactMatch bool
return criteriaEq
}
+// HLOOKUP function 'looks up' a given value in the top row of a data array
+// (or table), and returns the corresponding value from another row of the
+// array. The syntax of the function is:
+//
+// HLOOKUP(lookup_value,table_array,row_index_num,[range_lookup])
+//
+func (fn *formulaFuncs) HLOOKUP(argsList *list.List) formulaArg {
+ if argsList.Len() < 3 {
+ return newErrorFormulaArg(formulaErrorVALUE, "HLOOKUP requires at least 3 arguments")
+ }
+ if argsList.Len() > 4 {
+ return newErrorFormulaArg(formulaErrorVALUE, "HLOOKUP requires at most 4 arguments")
+ }
+ lookupValue := argsList.Front().Value.(formulaArg)
+ tableArray := argsList.Front().Next().Value.(formulaArg)
+ if tableArray.Type != ArgMatrix {
+ return newErrorFormulaArg(formulaErrorVALUE, "HLOOKUP requires second argument of table array")
+ }
+ rowArg := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
+ if rowArg.Type != ArgNumber {
+ return newErrorFormulaArg(formulaErrorVALUE, "HLOOKUP requires numeric row argument")
+ }
+ rowIdx, matchIdx, wasExact, exactMatch := int(rowArg.Number)-1, -1, false, false
+ if argsList.Len() == 4 {
+ rangeLookup := argsList.Back().Value.(formulaArg).ToBool()
+ if rangeLookup.Type == ArgError {
+ return newErrorFormulaArg(formulaErrorVALUE, rangeLookup.Error)
+ }
+ if rangeLookup.Number == 0 {
+ exactMatch = true
+ }
+ }
+ row := tableArray.Matrix[0]
+start:
+ for idx, mtx := range row {
+ switch compareFormulaArg(mtx, lookupValue, false, exactMatch) {
+ case criteriaL:
+ matchIdx = idx
+ case criteriaEq:
+ matchIdx = idx
+ wasExact = true
+ break start
+ }
+ }
+ if matchIdx == -1 {
+ return newErrorFormulaArg(formulaErrorNA, "HLOOKUP no result found")
+ }
+ if rowIdx < 0 || rowIdx >= len(tableArray.Matrix) {
+ return newErrorFormulaArg(formulaErrorNA, "HLOOKUP has invalid row index")
+ }
+ row = tableArray.Matrix[rowIdx]
+ if wasExact || !exactMatch {
+ return row[matchIdx]
+ }
+ return newErrorFormulaArg(formulaErrorNA, "HLOOKUP no result found")
+}
+
// 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 881077c..c72d78b 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -450,6 +450,7 @@ func TestCalcCellValue(t *testing.T) {
"=SUMSQ(A1,B1,A2,B2,6)": "82",
`=SUMSQ("",A1,B1,A2,B2,6)`: "82",
`=SUMSQ(1,SUMSQ(1))`: "2",
+ "=SUMSQ(MUNIT(3))": "0",
// TAN
"=TAN(1.047197551)": "1.732050806782486",
"=TAN(0)": "0",
@@ -560,6 +561,9 @@ func TestCalcCellValue(t *testing.T) {
"=CHOOSE(4,\"red\",\"blue\",\"green\",\"brown\")": "brown",
"=CHOOSE(1,\"red\",\"blue\",\"green\",\"brown\")": "red",
"=SUM(CHOOSE(A2,A1,B1:B2,A1:A3,A1:A4))": "9",
+ // HLOOKUP
+ "=HLOOKUP(D2,D2:D8,1,FALSE)": "Jan",
+ "=HLOOKUP(F3,F3:F8,3,FALSE)": "34440", // should be Feb
// VLOOKUP
"=VLOOKUP(D2,D:D,1,FALSE)": "Jan",
"=VLOOKUP(D2,D:D,1,TRUE)": "Month", // should be Feb
@@ -739,6 +743,8 @@ func TestCalcCellValue(t *testing.T) {
// LOG10
"=LOG10()": "LOG10 requires 1 numeric argument",
`=LOG10("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ // MDETERM
+ "MDETERM()": "MDETERM requires at least 1 argument",
// MOD
"=MOD()": "MOD requires 2 numeric arguments",
"=MOD(6,0)": "MOD divide by zero",
@@ -834,7 +840,8 @@ func TestCalcCellValue(t *testing.T) {
// SUMIF
"=SUMIF()": "SUMIF requires at least 2 argument",
// SUMSQ
- `=SUMSQ("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=SUMSQ("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ "=SUMSQ(C1:D2)": "strconv.ParseFloat: parsing \"Month\": invalid syntax",
// TAN
"=TAN()": "TAN requires 1 numeric argument",
`=TAN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
@@ -847,7 +854,8 @@ func TestCalcCellValue(t *testing.T) {
`=TRUNC(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// Statistical Functions
// MEDIAN
- "=MEDIAN()": "MEDIAN requires at least 1 argument",
+ "=MEDIAN()": "MEDIAN requires at least 1 argument",
+ "=MEDIAN(D1:D2)": "strconv.ParseFloat: parsing \"Month\": invalid syntax",
// Information Functions
// ISBLANK
"=ISBLANK(A1,A2)": "ISBLANK requires 1 argument",
@@ -914,6 +922,19 @@ func TestCalcCellValue(t *testing.T) {
"=CHOOSE()": "CHOOSE requires 2 arguments",
"=CHOOSE(\"index_num\",0)": "CHOOSE requires first argument of type number",
"=CHOOSE(2,0)": "index_num should be <= to the number of values",
+ // HLOOKUP
+ "=HLOOKUP()": "HLOOKUP requires at least 3 arguments",
+ "=HLOOKUP(D2,D1,1,FALSE)": "HLOOKUP requires second argument of table array",
+ "=HLOOKUP(D2,D:D,FALSE,FALSE)": "HLOOKUP requires numeric row argument",
+ "=HLOOKUP(D2,D:D,1,FALSE,FALSE)": "HLOOKUP requires at most 4 arguments",
+ "=HLOOKUP(D2,D:D,1,2)": "strconv.ParseBool: parsing \"2\": invalid syntax",
+ "=HLOOKUP(D2,D10:D10,1,FALSE)": "HLOOKUP no result found",
+ "=HLOOKUP(D2,D2:D3,4,FALSE)": "HLOOKUP has invalid row index",
+ "=HLOOKUP(D2,C:C,1,FALSE)": "HLOOKUP no result found",
+ "=HLOOKUP(ISNUMBER(1),F3:F9,1)": "HLOOKUP no result found",
+ "=HLOOKUP(INT(1),E2:E9,1)": "HLOOKUP no result found",
+ "=HLOOKUP(MUNIT(2),MUNIT(3),1)": "HLOOKUP no result found",
+ "=HLOOKUP(A1:B2,B2:B3,1)": "HLOOKUP no result found",
// VLOOKUP
"=VLOOKUP()": "VLOOKUP requires at least 3 arguments",
"=VLOOKUP(D2,D1,1,FALSE)": "VLOOKUP requires second argument of table array",