r(m, "AMORDEGRC", null);
r(m, "AMORLINC", null);
r(m, "AVERAGEIF", null);
- r(m, "AVERAGEIFS", null);
+ r(m, "AVERAGEIFS", Averageifs.instance);
r(m, "BAHTTEXT", null);
r(m, "BESSELI", null);
r(m, "BESSELJ", null);
r(m, "ISODD", ParityFunction.IS_ODD);
r(m, "JIS", null);
r(m, "LCM", null);
+ r(m, "MAXIFS", Maxifs.instance);
r(m, "MDURATION", null);
+ r(m, "MINIFS", Minifs.instance);
r(m, "MROUND", MRound.instance);
r(m, "MULTINOMIAL", null);
r(m, "NETWORKDAYS", NetworkdaysFunction.instance);
* @throws IllegalArgumentException if the function is unknown or already registered.
* @since 3.8 beta6
*/
- public static void registerFunction(String name, FreeRefFunction func){
+ public static void registerFunction(String name, FreeRefFunction func){
AnalysisToolPak inst = (AnalysisToolPak)instance;
if(!isATPFunction(name)) {
FunctionMetadata metaData = FunctionMetadataRegistry.getFunctionByName(name);
--- /dev/null
+/*
+ * ====================================================================
+ * 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.ErrorEval;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+
+/**
+ * Implementation for the Excel function AVERAGEIFS<p>
+ *
+ * Syntax : <p>
+ * AVERAGEIFS ( <b>average_range</b>, <b>criteria_range1</b>, <b>criteria1</b>,
+ * [<b>criteria_range2</b>, <b>criteria2</b>], ...)
+ * <ul>
+ * <li><b>min_range</b> Required. One or more cells to average, including numbers or names, ranges,
+ * or cell references that contain numbers. Blank and text values are ignored.</li>
+ * <li><b>criteria1_range</b> Required. The first range in which
+ * to evaluate the associated criteria.</li>
+ * <li><b>criteria1</b> Required. The criteria in the form of a number, expression,
+ * cell reference, or text that define which cells in the criteria_range1
+ * argument will be added</li>
+ * <li><b> criteria_range2, criteria2, ...</b> Optional. Additional ranges and their associated criteria.
+ * Up to 127 range/criteria pairs are allowed.
+ * </ul>
+ */
+public final class Averageifs extends Baseifs {
+ /**
+ * Singleton
+ */
+ public static final FreeRefFunction instance = new Averageifs();
+
+ /**
+ * https://support.microsoft.com/en-us/office/averageifs-function-48910c45-1fc0-4389-a028-f7c5c3001690
+ * AVERAGEIFS(average_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...)
+ * need at least 3 arguments and need to have an odd number of arguments (average_range plus x*(criteria_range, criteria))
+ */
+ @Override
+ protected boolean hasInitialRange() {
+ return true;
+ }
+
+ @Override
+ protected Aggregator createAggregator() {
+ return new Aggregator() {
+ Double sum = 0.0;
+ Integer count = 0;
+
+ @Override
+ public void addValue(ValueEval value) {
+ if(!(value instanceof NumberEval)) return;
+
+ double d = ((NumberEval) value).getNumberValue();;
+ sum += d;
+ count++;
+
+ }
+
+ @Override
+ public ValueEval getResult() {
+ return count == 0 ? ErrorEval.DIV_ZERO : new NumberEval(sum / count);
+ }
+ };
+ }
+}
* @return true if there should be a range argument before the criteria pairs
*/
protected abstract boolean hasInitialRange();
-
+
+ /**
+ * Implements the details of a specific aggregation function
+ */
+ protected static interface Aggregator {
+ void addValue(ValueEval d);
+ ValueEval getResult();
+ }
+
+ protected abstract Aggregator createAggregator();
+
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
final boolean hasInitialRange = hasInitialRange();
final int firstCriteria = hasInitialRange ? 1 : 0;
-
+
if( args.length < (2+firstCriteria) || args.length % 2 != firstCriteria ) {
return ErrorEval.VALUE_INVALID;
}
if (hasInitialRange) {
sumRange = convertRangeArg(args[0]);
}
-
+
// collect pairs of ranges and criteria
AreaEval[] ae = new AreaEval[(args.length - firstCriteria)/2];
I_MatchPredicate[] mp = new I_MatchPredicate[ae.length];
for(int i = firstCriteria, k=0; i < args.length; i += 2, k++){
ae[k] = convertRangeArg(args[i]);
-
+
mp[k] = Countif.createCriteriaPredicate(args[i+1], ec.getRowIndex(), ec.getColumnIndex());
}
validateCriteriaRanges(sumRange, ae);
validateCriteria(mp);
- double result = aggregateMatchingCells(sumRange, ae, mp);
- return new NumberEval(result);
+ return aggregateMatchingCells(createAggregator(), sumRange, ae, mp);
} catch (EvaluationException e) {
return e.getErrorEval();
}
private static void validateCriteriaRanges(AreaEval sumRange, AreaEval[] criteriaRanges) throws EvaluationException {
int h = criteriaRanges[0].getHeight();
int w = criteriaRanges[0].getWidth();
-
- if (sumRange != null
- && (sumRange.getHeight() != h
- || sumRange.getWidth() != w) ) {
+
+ if (sumRange != null
+ && (sumRange.getHeight() != h
+ || sumRange.getWidth() != w) ) {
throw EvaluationException.invalidValue();
}
-
+
for(AreaEval r : criteriaRanges){
if(r.getHeight() != h ||
- r.getWidth() != w ) {
+ r.getWidth() != w ) {
throw EvaluationException.invalidValue();
}
}
*/
private static void validateCriteria(I_MatchPredicate[] criteria) throws EvaluationException {
for(I_MatchPredicate predicate : criteria) {
-
+
// check for errors in predicate and return immediately using this error code
if(predicate instanceof ErrorMatcher) {
throw new EvaluationException(ErrorEval.valueOf(((ErrorMatcher)predicate).getValue()));
* @return the computed value
* @throws EvaluationException if there is an issue with eval
*/
- private static double aggregateMatchingCells(AreaEval sumRange, AreaEval[] ranges, I_MatchPredicate[] predicates)
+ private static ValueEval aggregateMatchingCells(Aggregator aggregator, AreaEval sumRange, AreaEval[] ranges, I_MatchPredicate[] predicates)
throws EvaluationException {
int height = ranges[0].getHeight();
int width = ranges[0].getWidth();
- double result = 0.0;
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) {
matches = false;
break;
}
-
}
- if(matches) { // sum only if all of the corresponding criteria specified are true for that cell.
- result += accumulate(sumRange, r, c);
+ if(matches) { // aggregate only if all of the corresponding criteria specified are true for that cell.
+ if(sumRange != null) {
+ ValueEval value = sumRange.getRelativeValue(r, c);
+ if (value instanceof ErrorEval) {
+ throw new EvaluationException((ErrorEval)value);
+ }
+ aggregator.addValue(value);
+ } else {
+ aggregator.addValue(null);
+ }
}
}
}
- return result;
- }
-
- /**
- * For counts, this would return 1, for sums it returns a cell value or zero.
- * This is only called after all the criteria are confirmed true for the coordinates.
- * @param sumRange if used
- * @param relRowIndex
- * @param relColIndex
- * @return the aggregate input value corresponding to the given range coordinates
- * @throws EvaluationException if there is an issue with eval
- */
- private static double accumulate(AreaEval sumRange, int relRowIndex, int relColIndex) throws EvaluationException {
- if (sumRange == null) return 1.0; // count
-
- ValueEval addend = sumRange.getRelativeValue(relRowIndex, relColIndex);
- if (addend instanceof NumberEval) {
- return ((NumberEval) addend).getNumberValue();
- } else if (addend instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval)addend);
- } else {
- // everything else (including string and boolean values) counts as zero
- return 0.0;
- }
+ return aggregator.getResult();
}
protected static AreaEval convertRangeArg(ValueEval eval) throws EvaluationException {
package org.apache.poi.ss.formula.functions;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+
/**
* Implementation for the function COUNTIFS
* <p>
protected boolean hasInitialRange() {
return false;
}
-}
+ @Override
+ protected Aggregator createAggregator() {
+ return new Aggregator() {
+ double accumulator = 0.0;
+
+ @Override
+ public void addValue(ValueEval value) {
+ accumulator += 1.0;
+ }
+
+ @Override
+ public ValueEval getResult() {
+ return new NumberEval(accumulator);
+ }
+ };
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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.ValueEval;
+
+/**
+ * Implementation for the Excel function MAXIFS<p>
+ *
+ * Syntax : <p>
+ * MAXIFS ( <b>max_range</b>, <b>criteria_range1</b>, <b>criteria1</b>,
+ * [<b>criteria_range2</b>, <b>criteria2</b>], ...)
+ * <ul>
+ * <li><b>min_range</b> Required. One or more cells to determine the maximum value of, including numbers or names, ranges,
+ * or cell references that contain numbers. Blank and text values are ignored.</li>
+ * <li><b>criteria1_range</b> Required. The first range in which
+ * to evaluate the associated criteria.</li>
+ * <li><b>criteria1</b> Required. The criteria in the form of a number, expression,
+ * cell reference, or text that define which cells in the criteria_range1
+ * argument will be added</li>
+ * <li><b> criteria_range2, criteria2, ...</b> Optional. Additional ranges and their associated criteria.
+ * Up to 127 range/criteria pairs are allowed.
+ * </ul>
+ */
+public final class Maxifs extends Baseifs {
+ /**
+ * Singleton
+ */
+ public static final FreeRefFunction instance = new Maxifs();
+
+ /**
+ * https://support.microsoft.com/en-us/office/maxifs-function-dfd611e6-da2c-488a-919b-9b6376b28883
+ * MAXIFS(max_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...)
+ * need at least 3 arguments and need to have an odd number of arguments (max-range plus x*(criteria_range, criteria))
+ */
+ @Override
+ protected boolean hasInitialRange() {
+ return true;
+ }
+
+ @Override
+ protected Aggregator createAggregator() {
+ return new Aggregator() {
+ Double accumulator = null;
+
+ @Override
+ public void addValue(ValueEval value) {
+ double d = (value instanceof NumberEval) ? ((NumberEval) value).getNumberValue() : 0.0;
+ if(accumulator == null || accumulator < d) {
+ accumulator = d;
+ }
+ }
+
+ @Override
+ public ValueEval getResult() {
+ return new NumberEval(accumulator == null ? 0.0 : accumulator);
+ }
+ };
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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.ValueEval;
+
+/**
+ * Implementation for the Excel function MINIFS<p>
+ *
+ * Syntax : <p>
+ * MINIFS ( <b>min_range</b>, <b>criteria_range1</b>, <b>criteria1</b>,
+ * [<b>criteria_range2</b>, <b>criteria2</b>], ...)
+ * <ul>
+ * <li><b>min_range</b> Required. One or more cells to determine the minimum value of, including numbers or names, ranges,
+ * or cell references that contain numbers. Blank and text values are ignored.</li>
+ * <li><b>criteria1_range</b> Required. The first range in which
+ * to evaluate the associated criteria.</li>
+ * <li><b>criteria1</b> Required. The criteria in the form of a number, expression,
+ * cell reference, or text that define which cells in the criteria_range1
+ * argument will be added</li>
+ * <li><b> criteria_range2, criteria2, ...</b> Optional. Additional ranges and their associated criteria.
+ * Up to 127 range/criteria pairs are allowed.
+ * </ul>
+ */
+public final class Minifs extends Baseifs {
+ /**
+ * Singleton
+ */
+ public static final FreeRefFunction instance = new Minifs();
+
+ /**
+ * https://support.microsoft.com/en-us/office/minifs-function-6ca1ddaa-079b-4e74-80cc-72eef32e6599
+ * MINIFS(min_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...
+ * need at least 3 arguments and need to have an odd number of arguments (min-range plus x*(criteria_range, criteria))
+ */
+ @Override
+ protected boolean hasInitialRange() {
+ return true;
+ }
+
+ @Override
+ protected Aggregator createAggregator() {
+ return new Aggregator() {
+ Double accumulator = null;
+
+ @Override
+ public void addValue(ValueEval value) {
+ double d = (value instanceof NumberEval) ? ((NumberEval) value).getNumberValue() : 0.0;
+ if(accumulator == null || accumulator > d) {
+ accumulator = d;
+ }
+ }
+
+ @Override
+ public ValueEval getResult() {
+ return new NumberEval(accumulator == null ? 0.0 : accumulator);
+ }
+ };
+ }
+}
package org.apache.poi.ss.formula.functions;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+
/**
* Implementation for the Excel function SUMIFS<p>
*
protected boolean hasInitialRange() {
return true;
}
+
+ @Override
+ protected Aggregator createAggregator() {
+ return new Aggregator() {
+ double accumulator = 0.0;
+
+ @Override
+ public void addValue(ValueEval value) {
+ accumulator += (value instanceof NumberEval) ? ((NumberEval) value).getNumberValue() : 0.0;
+ }
+
+ @Override
+ public ValueEval getResult() {
+ return new NumberEval(accumulator);
+ }
+ };
+ }
}
--- /dev/null
+/*
+ * ====================================================================
+ * 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 static org.apache.poi.ss.util.Utils.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.NumericValueEval;
+import org.apache.poi.ss.formula.eval.StringEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.usermodel.FormulaError;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+/**
+ * Test cases for AVERAGEIFS()
+ */
+final class TestAverageifs {
+
+ private static final OperationEvaluationContext EC = new OperationEvaluationContext(null, null, 0, 1, 0, null);
+
+ private static ValueEval invokeAverageifs(ValueEval[] args) {
+ return new Averageifs().evaluate(args, EC);
+ }
+
+ private static void confirmDouble(double expected, ValueEval actualEval) {
+ assertTrue(actualEval instanceof NumericValueEval, "Expected numeric result");
+ NumericValueEval nve = (NumericValueEval)actualEval;
+ assertEquals(expected, nve.getNumberValue(), 0);
+ }
+
+ private static void confirm(double expectedResult, ValueEval[] args) {
+ confirmDouble(expectedResult, invokeAverageifs(args));
+ }
+
+ private static void confirmError(ErrorEval errorEval, ValueEval[] args) {
+ ValueEval actualEval = invokeAverageifs(args);
+ assertEquals(errorEval, actualEval);
+ }
+
+ /**
+ * Example 1 from
+ * https://support.microsoft.com/en-us/office/maxifs-function-dfd611e6-da2c-488a-919b-9b6376b28883
+ */
+ @Test
+ void testExample1() {
+ ValueEval[] b2b5 = new ValueEval[] {
+ new StringEval("Quiz"),
+ new StringEval("Grade"),
+ new NumberEval(75),
+ new NumberEval(94)
+ };
+
+ ValueEval[] args;
+ // "=AVERAGEIFS(B2:B5, B2:B5, ">70", B2:B5, "<90")"
+ args = new ValueEval[]{
+ EvalFactory.createAreaEval("B2:B5", b2b5),
+ EvalFactory.createAreaEval("B2:B5", b2b5),
+ new StringEval(">70"),
+ EvalFactory.createAreaEval("B2:B5", b2b5),
+ new StringEval("<90")
+ };
+ confirm(75.0, args);
+
+ ValueEval[] c2c5 = new ValueEval[] {
+ new StringEval("Quiz"),
+ new StringEval("Grade"),
+ new NumberEval(85),
+ new NumberEval(80)
+ };
+ // "=AVERAGEIFS(C2:C5, C2:C5, ">95")"
+ args = new ValueEval[]{
+ EvalFactory.createAreaEval("C2:C5", c2c5),
+ EvalFactory.createAreaEval("C2:C5", c2c5),
+ new StringEval(">95")
+ };
+ confirmError(ErrorEval.DIV_ZERO, args);
+
+ }
+
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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 static org.apache.poi.ss.util.Utils.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.NumericValueEval;
+import org.apache.poi.ss.formula.eval.StringEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.usermodel.FormulaError;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+/**
+ * Test cases for MAXIFS()
+ */
+final class TestMaxifs {
+
+ private static final OperationEvaluationContext EC = new OperationEvaluationContext(null, null, 0, 1, 0, null);
+
+ private static ValueEval invokeMaxifs(ValueEval[] args) {
+ return new Maxifs().evaluate(args, EC);
+ }
+
+ private static void confirmDouble(double expected, ValueEval actualEval) {
+ assertTrue(actualEval instanceof NumericValueEval, "Expected numeric result");
+ NumericValueEval nve = (NumericValueEval)actualEval;
+ assertEquals(expected, nve.getNumberValue(), 0);
+ }
+
+ private static void confirm(double expectedResult, ValueEval[] args) {
+ confirmDouble(expectedResult, invokeMaxifs(args));
+ }
+
+ /**
+ * Example 1 from
+ * https://support.microsoft.com/en-us/office/maxifs-function-dfd611e6-da2c-488a-919b-9b6376b28883
+ */
+ @Test
+ void testExample1() {
+ ValueEval[] a2a7 = new ValueEval[] {
+ new NumberEval(89),
+ new NumberEval(93),
+ new NumberEval(96),
+ new NumberEval(85),
+ new NumberEval(91),
+ new NumberEval(88)
+ };
+
+ ValueEval[] b2b7 = new ValueEval[] {
+ new NumberEval(1),
+ new NumberEval(2),
+ new NumberEval(2),
+ new NumberEval(3),
+ new NumberEval(1),
+ new NumberEval(1)
+ };
+
+ ValueEval[] args;
+ // "=MAXIFS(A2:A7,B2:B7,1)"
+ args = new ValueEval[]{
+ EvalFactory.createAreaEval("A2:A7", a2a7),
+ EvalFactory.createAreaEval("B2:B7", b2b7),
+ new NumberEval(1)
+ };
+ confirm(91.0, args);
+
+ }
+
+ /**
+ * Example 2 from
+ * https://support.microsoft.com/en-us/office/maxifs-function-dfd611e6-da2c-488a-919b-9b6376b28883
+ */
+ @Test
+ void testExample2() {
+ ValueEval[] a2a5 = new ValueEval[] {
+ new NumberEval(10),
+ new NumberEval(11),
+ new NumberEval(100),
+ new NumberEval(111)
+ };
+
+ ValueEval[] b3b6 = new ValueEval[] {
+ new StringEval("a"),
+ new StringEval("a"),
+ new StringEval("b"),
+ new StringEval("a")
+ };
+
+ ValueEval[] args;
+
+ // "=MAXIFS(A2:A5,B3:B6,"a")"
+ args = new ValueEval[]{
+ EvalFactory.createAreaEval("A2:A5", a2a5),
+ EvalFactory.createAreaEval("B3:B6", b3b6),
+ new StringEval("a")
+ };
+ confirm(111.0, args); // the support article wrongly states 10.0
+ }
+
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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 static org.apache.poi.ss.util.Utils.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.NumericValueEval;
+import org.apache.poi.ss.formula.eval.StringEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.usermodel.FormulaError;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+/**
+ * Test cases for MINIFS()
+ */
+final class TestMinifs {
+
+ private static final OperationEvaluationContext EC = new OperationEvaluationContext(null, null, 0, 1, 0, null);
+
+ private static ValueEval invokeMinifs(ValueEval[] args) {
+ return new Minifs().evaluate(args, EC);
+ }
+
+ private static void confirmDouble(double expected, ValueEval actualEval) {
+ assertTrue(actualEval instanceof NumericValueEval, "Expected numeric result");
+ NumericValueEval nve = (NumericValueEval)actualEval;
+ assertEquals(expected, nve.getNumberValue(), 0);
+ }
+
+ private static void confirm(double expectedResult, ValueEval[] args) {
+ confirmDouble(expectedResult, invokeMinifs(args));
+ }
+
+ /**
+ * Example 1 from
+ * https://support.microsoft.com/en-us/office/minifs-function-6ca1ddaa-079b-4e74-80cc-72eef32e6599
+ */
+ @Test
+ void testExample1() {
+ ValueEval[] a2a7 = new ValueEval[] {
+ new NumberEval(89),
+ new NumberEval(93),
+ new NumberEval(96),
+ new NumberEval(85),
+ new NumberEval(91),
+ new NumberEval(88)
+ };
+
+ ValueEval[] b2b7 = new ValueEval[] {
+ new NumberEval(1),
+ new NumberEval(2),
+ new NumberEval(2),
+ new NumberEval(3),
+ new NumberEval(1),
+ new NumberEval(1)
+ };
+
+ ValueEval[] args;
+ // "=MINIFS(A2:A7,B2:B7,1)"
+ args = new ValueEval[]{
+ EvalFactory.createAreaEval("A2:A7", a2a7),
+ EvalFactory.createAreaEval("B2:B7", b2b7),
+ new NumberEval(1)
+ };
+ confirm(88.0, args);
+
+ }
+
+ /**
+ * Example 2 from
+ * https://support.microsoft.com/en-us/office/minifs-function-6ca1ddaa-079b-4e74-80cc-72eef32e6599
+ */
+ @Test
+ void testExample2() {
+ ValueEval[] a2a5 = new ValueEval[] {
+ new NumberEval(10),
+ new NumberEval(11),
+ new NumberEval(100),
+ new NumberEval(111)
+ };
+
+ ValueEval[] b3b6 = new ValueEval[] {
+ new StringEval("a"),
+ new StringEval("a"),
+ new StringEval("b"),
+ new StringEval("a")
+ };
+
+ ValueEval[] args;
+
+ // "=MINIFS(A2:A5,B3:B6,"a")"
+ args = new ValueEval[]{
+ EvalFactory.createAreaEval("A2:A5", a2a5),
+ EvalFactory.createAreaEval("B3:B6", b3b6),
+ new StringEval("a")
+ };
+ confirm(10.0, args);
+ }
+
+}