From e1abdb0e5a0ecae47dd0116c9165f4ad6e492856 Mon Sep 17 00:00:00 2001 From: xuri Date: Thu, 25 Mar 2021 00:05:02 +0800 Subject: [PATCH] This closes #809, and add new fn: HARMEAN --- calc.go | 35 +++++++++++++++++++++++++++++++++++ calc_test.go | 7 +++++++ styles.go | 4 ++-- xmlStyles.go | 4 ++-- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/calc.go b/calc.go index 8be52c76..04d0f8b9 100644 --- a/calc.go +++ b/calc.go @@ -282,6 +282,7 @@ var tokenPriority = map[string]int{ // GAMMA // GAMMALN // GCD +// HARMEAN // HEX2BIN // HEX2DEC // HEX2OCT @@ -3927,6 +3928,40 @@ func (fn *formulaFuncs) GAMMALN(argsList *list.List) formulaArg { return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument") } +// HARMEAN function calculates the harmonic mean of a supplied set of values. +// The syntax of the function is: +// +// HARMEAN(number1,[number2],...) +// +func (fn *formulaFuncs) HARMEAN(argsList *list.List) formulaArg { + if argsList.Len() < 1 { + return newErrorFormulaArg(formulaErrorVALUE, "HARMEAN requires at least 1 argument") + } + if min := fn.MIN(argsList); min.Number < 0 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + number, val, cnt := 0.0, 0.0, 0.0 + for token := argsList.Front(); token != nil; token = token.Next() { + arg := token.Value.(formulaArg) + switch arg.Type { + case ArgString: + num := arg.ToNumber() + if num.Type != ArgNumber { + continue + } + number = num.Number + case ArgNumber: + number = arg.Number + } + if number <= 0 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + val += (1 / number) + cnt++ + } + return newNumberFormulaArg(1 / (val / cnt)) +} + // KURT function calculates the kurtosis of a supplied set of values. The // syntax of the function is: // diff --git a/calc_test.go b/calc_test.go index f8397e77..65f7ce14 100644 --- a/calc_test.go +++ b/calc_test.go @@ -605,6 +605,9 @@ func TestCalcCellValue(t *testing.T) { // GAMMALN "=GAMMALN(4.5)": "2.453736570842443", "=GAMMALN(INT(1))": "0", + // HARMEAN + "=HARMEAN(2.5,3,0.5,1,3)": "1.229508196721312", + "=HARMEAN(\"2.5\",3,0.5,1,INT(3),\"\")": "1.229508196721312", // KURT "=KURT(F1:F9)": "-1.033503502551368", "=KURT(F1,F2:F9)": "-1.033503502551368", @@ -1393,6 +1396,10 @@ func TestCalcCellValue(t *testing.T) { "=GAMMALN(F1)": "GAMMALN requires 1 numeric argument", "=GAMMALN(0)": "#N/A", "=GAMMALN(INT(0))": "#N/A", + // HARMEAN + "=HARMEAN()": "HARMEAN requires at least 1 argument", + "=HARMEAN(-1)": "#N/A", + "=HARMEAN(0)": "#N/A", // KURT "=KURT()": "KURT requires at least 1 argument", "=KURT(F1,INT(1))": "#DIV/0!", diff --git a/styles.go b/styles.go index 06215f36..9e372393 100644 --- a/styles.go +++ b/styles.go @@ -2472,8 +2472,8 @@ func newAlignment(style *Style) *xlsxAlignment { func newProtection(style *Style) *xlsxProtection { var protection xlsxProtection if style.Protection != nil { - protection.Hidden = style.Protection.Hidden - protection.Locked = style.Protection.Locked + protection.Hidden = &style.Protection.Hidden + protection.Locked = &style.Protection.Locked } return &protection } diff --git a/xmlStyles.go b/xmlStyles.go index db85b159..0670b594 100644 --- a/xmlStyles.go +++ b/xmlStyles.go @@ -49,8 +49,8 @@ type xlsxAlignment struct { // set. The cell protection properties do not take effect unless the sheet has // been protected. type xlsxProtection struct { - Hidden bool `xml:"hidden,attr"` - Locked bool `xml:"locked,attr"` + Hidden *bool `xml:"hidden,attr"` + Locked *bool `xml:"locked,attr"` } // xlsxLine expresses a single set of cell border.