Skip to content

Commit 448dc5f

Browse files
committed
ref qax-os#65, new formula function: DAVERAGE
1 parent 2831072 commit 448dc5f

File tree

3 files changed

+73
-57
lines changed

3 files changed

+73
-57
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ test/excelize-*
1212
*.out
1313
*.test
1414
.idea
15+
.DS_Store

calc.go

+48-37
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ type formulaFuncs struct {
418418
// DATE
419419
// DATEDIF
420420
// DATEVALUE
421+
// DAVERAGE
421422
// DAY
422423
// DAYS
423424
// DAYS360
@@ -6008,7 +6009,7 @@ func (fn *formulaFuncs) AVERAGE(argsList *list.List) formulaArg {
60086009
}
60096010
count, sum := fn.countSum(false, args)
60106011
if count == 0 {
6011-
return newErrorFormulaArg(formulaErrorDIV, "AVERAGE divide by zero")
6012+
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
60126013
}
60136014
return newNumberFormulaArg(sum / count)
60146015
}
@@ -6025,7 +6026,7 @@ func (fn *formulaFuncs) AVERAGEA(argsList *list.List) formulaArg {
60256026
}
60266027
count, sum := fn.countSum(true, args)
60276028
if count == 0 {
6028-
return newErrorFormulaArg(formulaErrorDIV, "AVERAGEA divide by zero")
6029+
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
60296030
}
60306031
return newNumberFormulaArg(sum / count)
60316032
}
@@ -6075,7 +6076,7 @@ func (fn *formulaFuncs) AVERAGEIF(argsList *list.List) formulaArg {
60756076
}
60766077
count, sum := fn.countSum(false, args)
60776078
if count == 0 {
6078-
return newErrorFormulaArg(formulaErrorDIV, "AVERAGEIF divide by zero")
6079+
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
60796080
}
60806081
return newNumberFormulaArg(sum / count)
60816082
}
@@ -18068,6 +18069,42 @@ func (db *calcDatabase) next() bool {
1806818069
return matched
1806918070
}
1807018071

18072+
// database is an implementation of the formula functions DAVERAGE, DMAX and DMIN.
18073+
func (fn *formulaFuncs) database(name string, argsList *list.List) formulaArg {
18074+
if argsList.Len() != 3 {
18075+
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 arguments", name))
18076+
}
18077+
database := argsList.Front().Value.(formulaArg)
18078+
field := argsList.Front().Next().Value.(formulaArg)
18079+
criteria := argsList.Back().Value.(formulaArg)
18080+
db := newCalcDatabase(database, field, criteria)
18081+
if db == nil {
18082+
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
18083+
}
18084+
args := list.New()
18085+
for db.next() {
18086+
args.PushBack(db.value())
18087+
}
18088+
switch name {
18089+
case "DMAX":
18090+
return fn.MAX(args)
18091+
case "DMIN":
18092+
return fn.MIN(args)
18093+
default:
18094+
return fn.AVERAGE(args)
18095+
}
18096+
}
18097+
18098+
// DAVERAGE function calculates the average (statistical mean) of values in a
18099+
// field (column) in a database for selected records, that satisfy
18100+
// user-specified criteria. The syntax of the Excel Daverage function is:
18101+
//
18102+
// DAVERAGE(database,field,criteria)
18103+
//
18104+
func (fn *formulaFuncs) DAVERAGE(argsList *list.List) formulaArg {
18105+
return fn.database("DAVERAGE", argsList)
18106+
}
18107+
1807118108
// dcount is an implementation of the formula functions DCOUNT and DCOUNTA.
1807218109
func (fn *formulaFuncs) dcount(name string, argsList *list.List) formulaArg {
1807318110
if argsList.Len() < 2 {
@@ -18081,23 +18118,19 @@ func (fn *formulaFuncs) dcount(name string, argsList *list.List) formulaArg {
1808118118
if argsList.Len() > 2 {
1808218119
field = argsList.Front().Next().Value.(formulaArg)
1808318120
}
18084-
var count float64
1808518121
database := argsList.Front().Value.(formulaArg)
1808618122
db := newCalcDatabase(database, field, criteria)
1808718123
if db == nil {
1808818124
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
1808918125
}
18126+
args := list.New()
1809018127
for db.next() {
18091-
cell := db.value()
18092-
if cell.Value() == "" {
18093-
continue
18094-
}
18095-
if num := cell.ToNumber(); name == "DCOUNT" && num.Type != ArgNumber {
18096-
continue
18097-
}
18098-
count++
18128+
args.PushBack(db.value())
1809918129
}
18100-
return newNumberFormulaArg(count)
18130+
if name == "DCOUNT" {
18131+
return fn.COUNT(args)
18132+
}
18133+
return fn.COUNTA(args)
1810118134
}
1810218135

1810318136
// DCOUNT function returns the number of cells containing numeric values, in a
@@ -18122,28 +18155,6 @@ func (fn *formulaFuncs) DCOUNTA(argsList *list.List) formulaArg {
1812218155
return fn.dcount("DCOUNTA", argsList)
1812318156
}
1812418157

18125-
// dmaxmin is an implementation of the formula functions DMAX and DMIN.
18126-
func (fn *formulaFuncs) dmaxmin(name string, argsList *list.List) formulaArg {
18127-
if argsList.Len() != 3 {
18128-
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 arguments", name))
18129-
}
18130-
database := argsList.Front().Value.(formulaArg)
18131-
field := argsList.Front().Next().Value.(formulaArg)
18132-
criteria := argsList.Back().Value.(formulaArg)
18133-
db := newCalcDatabase(database, field, criteria)
18134-
if db == nil {
18135-
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
18136-
}
18137-
args := list.New()
18138-
for db.next() {
18139-
args.PushBack(db.value())
18140-
}
18141-
if name == "DMAX" {
18142-
return fn.MAX(args)
18143-
}
18144-
return fn.MIN(args)
18145-
}
18146-
1814718158
// DMAX function finds the maximum value in a field (column) in a database for
1814818159
// selected records only. The records to be included in the calculation are
1814918160
// defined by a set of one or more user-specified criteria. The syntax of the
@@ -18152,7 +18163,7 @@ func (fn *formulaFuncs) dmaxmin(name string, argsList *list.List) formulaArg {
1815218163
// DMAX(database,field,criteria)
1815318164
//
1815418165
func (fn *formulaFuncs) DMAX(argsList *list.List) formulaArg {
18155-
return fn.dmaxmin("DMAX", argsList)
18166+
return fn.database("DMAX", argsList)
1815618167
}
1815718168

1815818169
// DMIN function finds the minimum value in a field (column) in a database for
@@ -18163,5 +18174,5 @@ func (fn *formulaFuncs) DMAX(argsList *list.List) formulaArg {
1816318174
// DMIN(database,field,criteria)
1816418175
//
1816518176
func (fn *formulaFuncs) DMIN(argsList *list.List) formulaArg {
18166-
return fn.dmaxmin("DMIN", argsList)
18177+
return fn.database("DMIN", argsList)
1816718178
}

calc_test.go

+24-20
Original file line numberDiff line numberDiff line change
@@ -2655,14 +2655,14 @@ func TestCalcCellValue(t *testing.T) {
26552655
"=AVEDEV(\"\")": "#VALUE!",
26562656
"=AVEDEV(1,\"\")": "#VALUE!",
26572657
// AVERAGE
2658-
"=AVERAGE(H1)": "AVERAGE divide by zero",
2658+
"=AVERAGE(H1)": "#DIV/0!",
26592659
// AVERAGEA
2660-
"=AVERAGEA(H1)": "AVERAGEA divide by zero",
2660+
"=AVERAGEA(H1)": "#DIV/0!",
26612661
// AVERAGEIF
26622662
"=AVERAGEIF()": "AVERAGEIF requires at least 2 arguments",
2663-
"=AVERAGEIF(H1,\"\")": "AVERAGEIF divide by zero",
2664-
"=AVERAGEIF(D1:D3,\"Month\",D1:D3)": "AVERAGEIF divide by zero",
2665-
"=AVERAGEIF(C1:C3,\"Month\",D1:D3)": "AVERAGEIF divide by zero",
2663+
"=AVERAGEIF(H1,\"\")": "#DIV/0!",
2664+
"=AVERAGEIF(D1:D3,\"Month\",D1:D3)": "#DIV/0!",
2665+
"=AVERAGEIF(C1:C3,\"Month\",D1:D3)": "#DIV/0!",
26662666
// BETA.DIST
26672667
"=BETA.DIST()": "BETA.DIST requires at least 4 arguments",
26682668
"=BETA.DIST(0.4,4,5,TRUE,0,1,0)": "BETA.DIST requires at most 6 arguments",
@@ -4603,7 +4603,7 @@ func TestCalcCOVAR(t *testing.T) {
46034603
}
46044604
}
46054605

4606-
func TestCalcDCOUNTandDCOUNTAandDMAXandDMIN(t *testing.T) {
4606+
func TestCalcDatabase(t *testing.T) {
46074607
cellData := [][]interface{}{
46084608
{"Tree", "Height", "Age", "Yield", "Profit", "Height"},
46094609
{"=Apple", ">1000%", nil, nil, nil, "<16"},
@@ -4621,20 +4621,21 @@ func TestCalcDCOUNTandDCOUNTAandDMAXandDMIN(t *testing.T) {
46214621
assert.NoError(t, f.SetCellFormula("Sheet1", "A3", "=\"=Pear\""))
46224622
assert.NoError(t, f.SetCellFormula("Sheet1", "C8", "=NA()"))
46234623
formulaList := map[string]string{
4624-
"=DCOUNT(A4:E10,\"Age\",A1:F2)": "1",
4625-
"=DCOUNT(A4:E10,,A1:F2)": "2",
4626-
"=DCOUNT(A4:E10,\"Profit\",A1:F2)": "2",
4627-
"=DCOUNT(A4:E10,\"Tree\",A1:F2)": "0",
4628-
"=DCOUNT(A4:E10,\"Age\",A2:F3)": "0",
4629-
"=DCOUNTA(A4:E10,\"Age\",A1:F2)": "1",
4630-
"=DCOUNTA(A4:E10,,A1:F2)": "2",
4631-
"=DCOUNTA(A4:E10,\"Profit\",A1:F2)": "2",
4632-
"=DCOUNTA(A4:E10,\"Tree\",A1:F2)": "2",
4633-
"=DCOUNTA(A4:E10,\"Age\",A2:F3)": "0",
4634-
"=DMAX(A4:E10,\"Tree\",A1:F3)": "0",
4635-
"=DMAX(A4:E10,\"Profit\",A1:F3)": "96",
4636-
"=DMIN(A4:E10,\"Tree\",A1:F3)": "0",
4637-
"=DMIN(A4:E10,\"Profit\",A1:F3)": "45",
4624+
"=DCOUNT(A4:E10,\"Age\",A1:F2)": "1",
4625+
"=DCOUNT(A4:E10,,A1:F2)": "2",
4626+
"=DCOUNT(A4:E10,\"Profit\",A1:F2)": "2",
4627+
"=DCOUNT(A4:E10,\"Tree\",A1:F2)": "0",
4628+
"=DCOUNT(A4:E10,\"Age\",A2:F3)": "0",
4629+
"=DCOUNTA(A4:E10,\"Age\",A1:F2)": "1",
4630+
"=DCOUNTA(A4:E10,,A1:F2)": "2",
4631+
"=DCOUNTA(A4:E10,\"Profit\",A1:F2)": "2",
4632+
"=DCOUNTA(A4:E10,\"Tree\",A1:F2)": "2",
4633+
"=DCOUNTA(A4:E10,\"Age\",A2:F3)": "0",
4634+
"=DMAX(A4:E10,\"Tree\",A1:F3)": "0",
4635+
"=DMAX(A4:E10,\"Profit\",A1:F3)": "96",
4636+
"=DMIN(A4:E10,\"Tree\",A1:F3)": "0",
4637+
"=DMIN(A4:E10,\"Profit\",A1:F3)": "45",
4638+
"=DAVERAGE(A4:E10,\"Profit\",A1:F3)": "73.25",
46384639
}
46394640
for formula, expected := range formulaList {
46404641
assert.NoError(t, f.SetCellFormula("Sheet1", "A11", formula))
@@ -4659,6 +4660,9 @@ func TestCalcDCOUNTandDCOUNTAandDMAXandDMIN(t *testing.T) {
46594660
"=DMAX(A4:E10,\"x\",A1:F3)": "#VALUE!",
46604661
"=DMIN()": "DMIN requires 3 arguments",
46614662
"=DMIN(A4:E10,\"x\",A1:F3)": "#VALUE!",
4663+
"=DAVERAGE()": "DAVERAGE requires 3 arguments",
4664+
"=DAVERAGE(A4:E10,\"x\",A1:F3)": "#VALUE!",
4665+
"=DAVERAGE(A4:E10,\"Tree\",A1:F3)": "#DIV/0!",
46624666
}
46634667
for formula, expected := range calcError {
46644668
assert.NoError(t, f.SetCellFormula("Sheet1", "A11", formula))

0 commit comments

Comments
 (0)