From 94bec7638542b3cd6a636756e43db9355c1ace9f Mon Sep 17 00:00:00 2001 From: Greg Woolsey Date: Wed, 27 Dec 2017 22:33:03 +0000 Subject: [PATCH] Implement DMAX and DSUM functions, following the pattern from DMIN. Refactored the D* function enum to have instances return the function implementation instances rather than using a case construct, now that Java 8 is required. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1819376 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/formula/eval/FunctionEval.java | 5 +- .../apache/poi/ss/formula/functions/DMax.java | 60 ++++++++++++++++++ .../poi/ss/formula/functions/DStarRunner.java | 41 +++++++++--- .../apache/poi/ss/formula/functions/DSum.java | 49 ++++++++++++++ test-data/spreadsheet/DStar.xls | Bin 31232 -> 33280 bytes 5 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 src/java/org/apache/poi/ss/formula/functions/DMax.java create mode 100644 src/java/org/apache/poi/ss/formula/functions/DSum.java diff --git a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java index b327f25043..a3505d448b 100644 --- a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java +++ b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java @@ -106,10 +106,10 @@ public final class FunctionEval { retval[38] = BooleanFunction.NOT; retval[39] = NumericFunction.MOD; // 40: DCOUNT - // 41: DSUM + retval[41] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DSUM); // 42: DAVERAGE retval[43] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DMIN); - // 44: DMAX + retval[44] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DMAX); // 45: DSTDEV retval[46] = AggregateFunction.VAR; // 47: DVAR @@ -144,7 +144,6 @@ public final class FunctionEval { retval[FunctionID.OFFSET] = new Offset(); //nominally 78 retval[82] = TextFunction.SEARCH; - // 83: TRANSPOSE retval[83] = MatrixFunction.TRANSPOSE; // 86: TYPE diff --git a/src/java/org/apache/poi/ss/formula/functions/DMax.java b/src/java/org/apache/poi/ss/formula/functions/DMax.java new file mode 100644 index 0000000000..4d442f0415 --- /dev/null +++ b/src/java/org/apache/poi/ss/formula/functions/DMax.java @@ -0,0 +1,60 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.formula.functions; + +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.NumericValueEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Implementation of the DMax function: + * Finds the maximum value of a column in an area with given conditions. + * + * TODO: + * - wildcards ? and * in string conditions + * - functions as conditions + */ +public final class DMax implements IDStarAlgorithm { + private ValueEval maximumValue; + + @Override + public boolean processMatch(ValueEval eval) { + if(eval instanceof NumericValueEval) { + if(maximumValue == null) { // First match, just set the value. + maximumValue = eval; + } else { // There was a previous match, find the new minimum. + double currentValue = ((NumericValueEval)eval).getNumberValue(); + double oldValue = ((NumericValueEval)maximumValue).getNumberValue(); + if(currentValue > oldValue) { + maximumValue = eval; + } + } + } + + return true; + } + + @Override + public ValueEval getResult() { + if(maximumValue == null) { + return NumberEval.ZERO; + } else { + return maximumValue; + } + } +} diff --git a/src/java/org/apache/poi/ss/formula/functions/DStarRunner.java b/src/java/org/apache/poi/ss/formula/functions/DStarRunner.java index 6a43a62047..a1f92e781c 100644 --- a/src/java/org/apache/poi/ss/formula/functions/DStarRunner.java +++ b/src/java/org/apache/poi/ss/formula/functions/DStarRunner.java @@ -17,6 +17,8 @@ package org.apache.poi.ss.formula.functions; +import java.util.function.Supplier; + import org.apache.poi.ss.formula.eval.AreaEval; import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.ErrorEval; @@ -39,13 +41,38 @@ import org.apache.poi.ss.util.NumberComparer; * - functions as conditions */ public final class DStarRunner implements Function3Arg { + /** + * Enum for convenience to identify and source implementations of the D* functions + */ public enum DStarAlgorithmEnum { - DGET, - DMIN, - // DMAX, // DMAX is not yet implemented + /** @see DGet */ + DGET(DGet::new), + /** @see DMin */ + DMIN(DMin::new), + /** @see DMax */ + DMAX(DMax::new), + /** @see DSum */ + DSUM(DSum::new), + ; + + private final Supplier implSupplier; + + private DStarAlgorithmEnum(Supplier implSupplier) { + this.implSupplier = implSupplier; + } + + /** + * @return a new function implementation instance + */ + public IDStarAlgorithm newInstance() { + return implSupplier.get(); + } } private final DStarAlgorithmEnum algoType; + /** + * @param algorithm to implement + */ public DStarRunner(DStarAlgorithmEnum algorithm) { this.algoType = algorithm; } @@ -86,13 +113,7 @@ public final class DStarRunner implements Function3Arg { } // Create an algorithm runner. - IDStarAlgorithm algorithm; - switch(algoType) { - case DGET: algorithm = new DGet(); break; - case DMIN: algorithm = new DMin(); break; - default: - throw new IllegalStateException("Unexpected algorithm type " + algoType + " encountered."); - } + IDStarAlgorithm algorithm = algoType.newInstance(); // Iterate over all DB entries. final int height = db.getHeight(); diff --git a/src/java/org/apache/poi/ss/formula/functions/DSum.java b/src/java/org/apache/poi/ss/formula/functions/DSum.java new file mode 100644 index 0000000000..26604677de --- /dev/null +++ b/src/java/org/apache/poi/ss/formula/functions/DSum.java @@ -0,0 +1,49 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.formula.functions; + +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.NumericValueEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Implementation of the DSum function: + * Finds the total value of matching values in a column in an area with given conditions. + * + * TODO: + * - wildcards ? and * in string conditions + * - functions as conditions + */ +public final class DSum implements IDStarAlgorithm { + private double totalValue = 0; + + @Override + public boolean processMatch(ValueEval eval) { + if(eval instanceof NumericValueEval) { + double currentValue = ((NumericValueEval)eval).getNumberValue(); + totalValue += currentValue; + } + + return true; + } + + @Override + public ValueEval getResult() { + return new NumberEval(totalValue); + } +} diff --git a/test-data/spreadsheet/DStar.xls b/test-data/spreadsheet/DStar.xls index 0c89261426a89341c1521de4db5a393b5fa3ee9a..8a5a45d7ef399cd619b71220dfd5ac90f1e44f8b 100644 GIT binary patch delta 7250 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 delta 5535 zcmai2du*H46+id$=lGF_UAu|nJe<#YHSgLk`t z{dAw_+}}C(oO{pxzHjycZT8>dOhDXpHdv~6648a*o);Vwwl(|L{lW6v1wlC$qHCnl z3;Jc0M1Mmbpb2sj9UeV#A{03>6b>7`L($0S(J}7P`ngxr`JDEk@Umg@XDr{;{i1*u z^=6cYX(e}=^U(_E#r6(*Sqjle5{mg-x=pbZ^J`13=aMaZ7o8CaW;u6La;{KN?a8i! zvbU!)+pbg3n58y`sVGk)Pm+s(;TNQ|STNa&$Rf7T5RKC)9ia$HpWa4h9<_9c9Dd5u zEi8P^ve|50wr>s#?&+l5prY7p*t2Q5h-9 zqH+FBo6qDe#Bx548ALClA(Q^B@fNM5LjEY%lY#o(1oc8*ChCO*^;G`U z>lvxPN>D|C!M|`ggoA?x9VagyrhYYu~N z&s$+_Ow8ur0d~&eGnvW8KQ8b&m#pyV@Mx)1H1c%mBch2NWrsvFA1@1t7JjsBt5~f#W-6R~uB?E|%Ga8M5MklV zD@yn^kIr8ykBHVJk7(l(-&P*1@bSGqw^+kx(EE0Uogej;@~1w73(Di|t_nk}<1bYN z#Ckqcv6bH|_w$6y$%DQEe%MtdHt<>_VBV-Co$~njo5sgoZgNrqQER}cF`A8@vFT7a z8l1E4r8#NcL=w6$RzR&3AcJar?@&dsk?c>z--VcNgI zD;0og&)}8nYN?4Q4I+bAs zNrTAXnblb!78FEj8bk)qv}J*ip6RTW_9&Au9be!X127#KJo9j^TugZyLiu%)RAT5%eF6s-SdLS_g!4|l!YOTt z<8(Ht?nI(1cgYVMyum!GBMVW_)a0?DBcVC#S5x)U3KiZIP0}%3h({>IJ&j)89o*9C zz&&aw+8m06jvfzBg^$fyXO>MairHy1h43a4qN8-2!Zd|^3=jjOIyKDZ#OAC`sdLOZ zv0T~;{%O3uoKWvF2Hk=Ed8dl-tmRRoRCwEHIJ3elq3|}$g`9-K-Kz)M^Kpsdn%EXO z7CI6hot(4wrHVCqV^&OyU{VOH3`|xoOL*Lre?>?J(wAV^3(iMVCS$-t+Qsxs7~cH zn_;6~=zbDb4q>s;gq(b8lUC|GdVCx{#S*rpP86lEQlE0=I3`M$M)|FV>VQr(OAxen z89yohC>A1(Gz5{u5Ty~HuXN8iaUAAq9NmOXnY*!{y?hXwc?nQ4l1*c!FP-Jl#)gd;dSaT%5gj){`2bE8J#+3^$c4~ z#}@0y0XYuGsY9RGVmjS4YXSfAV{d_@Q~6Vmy_+`3(Az&039D0R><`_I{Zg}RhibWq zz5QyZg`wy5qv_%2TWxz-E2NFm0BY67BDUT{WN{=Ep0hr*%m5x3U}>pX_F`fePGCWc zFb2T+O5K738#(B+lWqY=l8ciEBX2H9X$>^-KQiF z{cOxZIsD%p|0wr@^)tkGsjx#@O!eefuY*cBcJn*6sY39flt`;3&n}`Zw-MFsgPDdl4&_C7r}oDls|!N;!gT^jK~? zVxWNC4`~ARA@Fwk2()3>GfmJ+B?O;q>>hW`Q@%qo8mP~Y|d zOaj}UoEXJj776a%fx{Z0?TGwqpvYzf#b$)69<+jJZN_LD`mz;7Xy{OV06@Jrs7}kE zUjB9csHdI%JG%3_XuaX_={U%CsC&2b{tq zd+@F-%VcS;fb<;x=Yc9w%J~PMcgVgxSvu-2^7HQxb`^bIN;UY2g)7WL9uo~63)R>u zmn-@WfOPk7!0GxdGs`1jDd(T|?=#5>_Ctp7apR#D)f+fu%oqu2(gqGZaoKiAa=@I) zUQSBSf}S+H)Y6U!biJ3W=1I*ZEf*R)Fp})ac`^>fX>wli47x&#vvsMK6BFVsdHCWj z&(c`&QmbsKRiRo}Z~$I~20Xnk=G#ORzdh9*pq1e{73gY#M!%? bbF-gl-`U6inVrTjqp8y~d99$TlaK0u`i}}(