mirror of https://github.com/apache/poi.git
Removing calls to AreaEval.getValues() from count and lookup functions
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690112 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
76964bdcba
commit
4897063eab
|
@ -1,23 +1,20 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 8, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
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.hssf.record.formula.eval;
|
||||
|
||||
/**
|
||||
|
@ -72,13 +69,9 @@ public interface AreaEval extends ValueEval {
|
|||
ValueEval[] getValues();
|
||||
|
||||
/**
|
||||
* returns the ValueEval from the values array at the specified
|
||||
* row and col index. The specified indexes should be absolute indexes
|
||||
* in the sheet and not relative indexes within the area. Also,
|
||||
* if contains(row, col) evaluates to true, a null value will
|
||||
* bre returned.
|
||||
* @param row
|
||||
* @param col
|
||||
* @return the ValueEval from within this area at the specified row and col index. Never
|
||||
* <code>null</code> (possibly {@link BlankEval}). The specified indexes should be absolute
|
||||
* indexes in the sheet and not relative indexes within the area.
|
||||
*/
|
||||
ValueEval getValueAt(int row, int col);
|
||||
|
||||
|
@ -105,5 +98,10 @@ public interface AreaEval extends ValueEval {
|
|||
|
||||
int getWidth();
|
||||
int getHeight();
|
||||
/**
|
||||
* @return the ValueEval from within this area at the specified relativeRowIndex and
|
||||
* relativeColumnIndex. Never <code>null</code> (possibly {@link BlankEval}). The
|
||||
* specified indexes should relative to the top left corner of this area.
|
||||
*/
|
||||
ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* ====================================================================
|
||||
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.hssf.record.formula.eval;
|
||||
|
||||
|
@ -123,7 +123,11 @@ abstract class AreaEvalBase implements AreaEval {
|
|||
|
||||
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||
int index = relativeRowIndex * _nColumns + relativeColumnIndex;
|
||||
return _values[index];
|
||||
ValueEval result = _values[index];
|
||||
if (result == null) {
|
||||
return BlankEval.INSTANCE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
|
|
|
@ -1,30 +1,27 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 9, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
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.hssf.record.formula.eval;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com > This class is a
|
||||
* marker class. It is a special value for empty cells.
|
||||
*/
|
||||
public class BlankEval implements ValueEval {
|
||||
public final class BlankEval implements ValueEval {
|
||||
|
||||
public static BlankEval INSTANCE = new BlankEval();
|
||||
|
||||
|
|
|
@ -1,32 +1,26 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 15, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
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.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.AreaEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.BlankEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
|
||||
|
||||
/**
|
||||
* Counts the number of cells that contain numeric data within
|
||||
|
@ -39,7 +33,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
|||
* TODO: Check this properly matches excel on edge cases
|
||||
* like formula cells, error cells etc
|
||||
*/
|
||||
public class Count implements Function {
|
||||
public final class Count implements Function {
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
int nArgs = args.length;
|
||||
|
@ -56,63 +50,23 @@ public class Count implements Function {
|
|||
int temp = 0;
|
||||
|
||||
for(int i=0; i<nArgs; i++) {
|
||||
temp += countArg(args[i]);
|
||||
temp += CountUtils.countArg(args[i], predicate);
|
||||
|
||||
}
|
||||
return new NumberEval(temp);
|
||||
}
|
||||
|
||||
private static int countArg(Eval eval) {
|
||||
if (eval instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) eval;
|
||||
return countAreaEval(ae);
|
||||
}
|
||||
if (eval instanceof RefEval) {
|
||||
RefEval refEval = (RefEval)eval;
|
||||
return countValue(refEval.getInnerValueEval());
|
||||
}
|
||||
if (eval instanceof NumberEval) {
|
||||
return 1;
|
||||
private static final I_MatchPredicate predicate = new I_MatchPredicate() {
|
||||
|
||||
public boolean matches(Eval valueEval) {
|
||||
|
||||
if(valueEval instanceof NumberEval) {
|
||||
// only numbers are counted
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unexpected eval type (" + eval.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
private static int countAreaEval(AreaEval ae) {
|
||||
|
||||
int temp = 0;
|
||||
ValueEval[] values = ae.getValues();
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
ValueEval val = values[i];
|
||||
if(val == null) {
|
||||
// seems to occur. Really we would have expected BlankEval
|
||||
continue;
|
||||
}
|
||||
temp += countValue(val);
|
||||
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
private static int countValue(ValueEval valueEval) {
|
||||
|
||||
if(valueEval == BlankEval.INSTANCE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(valueEval instanceof BlankEval) {
|
||||
// wouldn't need this if BlankEval was final
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(valueEval instanceof ErrorEval) {
|
||||
// note - error values not counted
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(valueEval instanceof NumberEval)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
// error values and string values not counted
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/* ====================================================================
|
||||
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.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.AreaEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
/**
|
||||
* Common logic for COUNT, COUNTA and COUNTIF
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class CountUtils {
|
||||
|
||||
private CountUtils() {
|
||||
// no instances of this class
|
||||
}
|
||||
|
||||
/**
|
||||
* Common interface for the matching criteria.
|
||||
*/
|
||||
public interface I_MatchPredicate {
|
||||
boolean matches(Eval x);
|
||||
}
|
||||
/**
|
||||
* @return the number of evaluated cells in the range that match the specified criteria
|
||||
*/
|
||||
public static int countMatchingCellsInArea(AreaEval areaEval, I_MatchPredicate criteriaPredicate) {
|
||||
int result = 0;
|
||||
|
||||
int height = areaEval.getHeight();
|
||||
int width = areaEval.getWidth();
|
||||
for (int rrIx=0; rrIx<height; rrIx++) {
|
||||
for (int rcIx=0; rcIx<width; rcIx++) {
|
||||
ValueEval ve = areaEval.getRelativeValue(rrIx, rcIx);
|
||||
if(criteriaPredicate.matches(ve)) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @return 1 if the evaluated cell matches the specified criteria
|
||||
*/
|
||||
public static int countMatchingCell(RefEval refEval, I_MatchPredicate criteriaPredicate) {
|
||||
if(criteriaPredicate.matches(refEval.getInnerValueEval())) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public static int countArg(Eval eval, I_MatchPredicate criteriaPredicate) {
|
||||
if (eval instanceof AreaEval) {
|
||||
return CountUtils.countMatchingCellsInArea((AreaEval) eval, criteriaPredicate);
|
||||
}
|
||||
if (eval instanceof RefEval) {
|
||||
return CountUtils.countMatchingCell((RefEval) eval, criteriaPredicate);
|
||||
}
|
||||
return criteriaPredicate.matches(eval) ? 1 : 0;
|
||||
}
|
||||
}
|
|
@ -1,31 +1,27 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* ====================================================================
|
||||
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.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.AreaEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.BlankEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
|
||||
|
||||
/**
|
||||
* Counts the number of cells that contain data within the list of arguments.
|
||||
|
@ -51,70 +47,26 @@ public final class Counta implements Function {
|
|||
}
|
||||
|
||||
int temp = 0;
|
||||
// Note - observed behavior of Excel:
|
||||
// Error values like #VALUE!, #REF!, #DIV/0!, #NAME? etc don't cause this COUNTA to return an error
|
||||
// in fact, they seem to get counted
|
||||
|
||||
for(int i=0; i<nArgs; i++) {
|
||||
temp += countArg(args[i]);
|
||||
temp += CountUtils.countArg(args[i], predicate);
|
||||
|
||||
}
|
||||
return new NumberEval(temp);
|
||||
}
|
||||
|
||||
private static int countArg(Eval eval) {
|
||||
if (eval instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) eval;
|
||||
return countAreaEval(ae);
|
||||
}
|
||||
if (eval instanceof RefEval) {
|
||||
RefEval refEval = (RefEval)eval;
|
||||
return countValue(refEval.getInnerValueEval());
|
||||
}
|
||||
if (eval instanceof NumberEval) {
|
||||
return 1;
|
||||
}
|
||||
if (eval instanceof StringEval) {
|
||||
return 1;
|
||||
}
|
||||
private static final I_MatchPredicate predicate = new I_MatchPredicate() {
|
||||
|
||||
|
||||
throw new RuntimeException("Unexpected eval type (" + eval.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
private static int countAreaEval(AreaEval ae) {
|
||||
|
||||
int temp = 0;
|
||||
ValueEval[] values = ae.getValues();
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
ValueEval val = values[i];
|
||||
if(val == null) {
|
||||
// seems to occur. Really we would have expected BlankEval
|
||||
continue;
|
||||
}
|
||||
temp += countValue(val);
|
||||
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
private static int countValue(ValueEval valueEval) {
|
||||
public boolean matches(Eval valueEval) {
|
||||
// Note - observed behavior of Excel:
|
||||
// Error values like #VALUE!, #REF!, #DIV/0!, #NAME? etc don't cause this COUNTA to return an error
|
||||
// in fact, they seem to get counted
|
||||
|
||||
if(valueEval == BlankEval.INSTANCE) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(valueEval instanceof BlankEval) {
|
||||
// wouldn't need this if BlankEval was final
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(valueEval instanceof ErrorEval) {
|
||||
// note - error values are counted
|
||||
return 1;
|
||||
}
|
||||
// also empty strings and zeros are counted too
|
||||
|
||||
return 1;
|
||||
// Note - everything but BlankEval counts
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* ====================================================================
|
||||
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.hssf.record.formula.functions;
|
||||
|
||||
|
@ -28,7 +28,7 @@ import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
|||
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
|
||||
|
||||
/**
|
||||
* Implementation for the function COUNTIF<p/>
|
||||
|
@ -144,12 +144,6 @@ public final class Countif implements Function {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Common interface for the matching criteria.
|
||||
*/
|
||||
/* package */ interface I_MatchPredicate {
|
||||
boolean matches(Eval x);
|
||||
}
|
||||
|
||||
private static final class NumberMatcher implements I_MatchPredicate {
|
||||
|
||||
|
@ -360,21 +354,12 @@ public final class Countif implements Function {
|
|||
* @return the number of evaluated cells in the range that match the specified criteria
|
||||
*/
|
||||
private Eval countMatchingCellsInArea(Eval rangeArg, I_MatchPredicate criteriaPredicate) {
|
||||
int result = 0;
|
||||
if (rangeArg instanceof RefEval) {
|
||||
RefEval refEval = (RefEval) rangeArg;
|
||||
if(criteriaPredicate.matches(refEval.getInnerValueEval())) {
|
||||
result++;
|
||||
}
|
||||
} else if (rangeArg instanceof AreaEval) {
|
||||
|
||||
AreaEval range = (AreaEval) rangeArg;
|
||||
ValueEval[] values = range.getValues();
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if(criteriaPredicate.matches(values[i])) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
int result;
|
||||
if (rangeArg instanceof RefEval) {
|
||||
result = CountUtils.countMatchingCell((RefEval) rangeArg, criteriaPredicate);
|
||||
} else if (rangeArg instanceof AreaEval) {
|
||||
result = CountUtils.countMatchingCellsInArea((AreaEval) rangeArg, criteriaPredicate);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Bad range arg type (" + rangeArg.getClass().getName() + ")");
|
||||
}
|
||||
|
|
|
@ -42,40 +42,6 @@ import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
|
|||
*/
|
||||
public final class Hlookup implements Function {
|
||||
|
||||
private static final class RowVector implements ValueVector {
|
||||
|
||||
private final AreaEval _tableArray;
|
||||
private final int _size;
|
||||
private final int _rowAbsoluteIndex;
|
||||
private final int _firstColumnAbsoluteIndex;
|
||||
|
||||
public RowVector(AreaEval tableArray, int rowIndex) {
|
||||
_rowAbsoluteIndex = tableArray.getFirstRow() + rowIndex;
|
||||
if(!tableArray.containsRow(_rowAbsoluteIndex)) {
|
||||
int lastRowIx = tableArray.getLastRow() - tableArray.getFirstRow();
|
||||
throw new IllegalArgumentException("Specified row index (" + rowIndex
|
||||
+ ") is outside the allowed range (0.." + lastRowIx + ")");
|
||||
}
|
||||
_tableArray = tableArray;
|
||||
_size = tableArray.getLastColumn() - tableArray.getFirstColumn() + 1;
|
||||
if(_size < 1) {
|
||||
throw new RuntimeException("bad table array size zero");
|
||||
}
|
||||
_firstColumnAbsoluteIndex = tableArray.getFirstColumn();
|
||||
}
|
||||
|
||||
public ValueEval getItem(int index) {
|
||||
if(index>_size) {
|
||||
throw new ArrayIndexOutOfBoundsException("Specified index (" + index
|
||||
+ ") is outside the allowed range (0.." + (_size-1) + ")");
|
||||
}
|
||||
return _tableArray.getValueAt(_rowAbsoluteIndex, (short) (_firstColumnAbsoluteIndex + index));
|
||||
}
|
||||
public int getSize() {
|
||||
return _size;
|
||||
}
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
Eval arg3 = null;
|
||||
switch(args.length) {
|
||||
|
@ -93,7 +59,7 @@ public final class Hlookup implements Function {
|
|||
ValueEval lookupValue = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
|
||||
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
|
||||
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
|
||||
int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, new RowVector(tableArray, 0), isRangeLookup);
|
||||
int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup);
|
||||
ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
|
||||
int rowIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
|
||||
ValueVector resultCol = createResultColumnVector(tableArray, rowIndex);
|
||||
|
@ -113,11 +79,9 @@ public final class Hlookup implements Function {
|
|||
if(colIndex < 0) {
|
||||
throw EvaluationException.invalidValue();
|
||||
}
|
||||
int nCols = tableArray.getLastColumn() - tableArray.getFirstRow() + 1;
|
||||
|
||||
if(colIndex >= nCols) {
|
||||
if(colIndex >= tableArray.getWidth()) {
|
||||
throw EvaluationException.invalidRef();
|
||||
}
|
||||
return new RowVector(tableArray, colIndex);
|
||||
return LookupUtils.createRowVector(tableArray, colIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,19 +40,6 @@ import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
|
|||
* @author Josh Micich
|
||||
*/
|
||||
public final class Lookup implements Function {
|
||||
private static final class SimpleValueVector implements ValueVector {
|
||||
private final ValueEval[] _values;
|
||||
|
||||
public SimpleValueVector(ValueEval[] values) {
|
||||
_values = values;
|
||||
}
|
||||
public ValueEval getItem(int index) {
|
||||
return _values[index];
|
||||
}
|
||||
public int getSize() {
|
||||
return _values.length;
|
||||
}
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
switch(args.length) {
|
||||
|
@ -86,11 +73,11 @@ public final class Lookup implements Function {
|
|||
}
|
||||
|
||||
private static ValueVector createVector(AreaEval ae) {
|
||||
|
||||
if(!ae.isRow() && !ae.isColumn()) {
|
||||
ValueVector result = LookupUtils.createVector(ae);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// extra complexity required to emulate the way LOOKUP can handles these abnormal cases.
|
||||
throw new RuntimeException("non-vector lookup or result areas not supported yet");
|
||||
}
|
||||
return new SimpleValueVector(ae.getValues());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,87 @@ final class LookupUtils {
|
|||
ValueEval getItem(int index);
|
||||
int getSize();
|
||||
}
|
||||
|
||||
|
||||
private static final class RowVector implements ValueVector {
|
||||
|
||||
private final AreaEval _tableArray;
|
||||
private final int _size;
|
||||
private final int _rowIndex;
|
||||
|
||||
public RowVector(AreaEval tableArray, int rowIndex) {
|
||||
_rowIndex = rowIndex;
|
||||
int _rowAbsoluteIndex = tableArray.getFirstRow() + rowIndex;
|
||||
if(!tableArray.containsRow(_rowAbsoluteIndex)) {
|
||||
int lastRowIx = tableArray.getLastRow() - tableArray.getFirstRow();
|
||||
throw new IllegalArgumentException("Specified row index (" + rowIndex
|
||||
+ ") is outside the allowed range (0.." + lastRowIx + ")");
|
||||
}
|
||||
_tableArray = tableArray;
|
||||
_size = tableArray.getWidth();
|
||||
}
|
||||
|
||||
public ValueEval getItem(int index) {
|
||||
if(index > _size) {
|
||||
throw new ArrayIndexOutOfBoundsException("Specified index (" + index
|
||||
+ ") is outside the allowed range (0.." + (_size-1) + ")");
|
||||
}
|
||||
return _tableArray.getRelativeValue(_rowIndex, index);
|
||||
}
|
||||
public int getSize() {
|
||||
return _size;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ColumnVector implements ValueVector {
|
||||
|
||||
private final AreaEval _tableArray;
|
||||
private final int _size;
|
||||
private final int _columnIndex;
|
||||
|
||||
public ColumnVector(AreaEval tableArray, int columnIndex) {
|
||||
_columnIndex = columnIndex;
|
||||
int _columnAbsoluteIndex = tableArray.getFirstColumn() + columnIndex;
|
||||
if(!tableArray.containsColumn((short)_columnAbsoluteIndex)) {
|
||||
int lastColIx = tableArray.getLastColumn() - tableArray.getFirstColumn();
|
||||
throw new IllegalArgumentException("Specified column index (" + columnIndex
|
||||
+ ") is outside the allowed range (0.." + lastColIx + ")");
|
||||
}
|
||||
_tableArray = tableArray;
|
||||
_size = _tableArray.getHeight();
|
||||
}
|
||||
|
||||
public ValueEval getItem(int index) {
|
||||
if(index > _size) {
|
||||
throw new ArrayIndexOutOfBoundsException("Specified index (" + index
|
||||
+ ") is outside the allowed range (0.." + (_size-1) + ")");
|
||||
}
|
||||
return _tableArray.getRelativeValue(index, _columnIndex);
|
||||
}
|
||||
public int getSize() {
|
||||
return _size;
|
||||
}
|
||||
}
|
||||
|
||||
public static ValueVector createRowVector(AreaEval tableArray, int relativeRowIndex) {
|
||||
return new RowVector(tableArray, relativeRowIndex);
|
||||
}
|
||||
public static ValueVector createColumnVector(AreaEval tableArray, int relativeColumnIndex) {
|
||||
return new ColumnVector(tableArray, relativeColumnIndex);
|
||||
}
|
||||
/**
|
||||
* @return <code>null</code> if the supplied area is neither a single row nor a single colum
|
||||
*/
|
||||
public static ValueVector createVector(AreaEval ae) {
|
||||
if (ae.isColumn()) {
|
||||
return createColumnVector(ae, 0);
|
||||
}
|
||||
if (ae.isRow()) {
|
||||
return createRowVector(ae, 0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration to support <b>4</b> valued comparison results.<p/>
|
||||
* Excel lookup functions have complex behaviour in the case where the lookup array has mixed
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.poi.hssf.record.formula.eval.StringEval;
|
|||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.functions.LookupUtils.CompareResult;
|
||||
import org.apache.poi.hssf.record.formula.functions.LookupUtils.LookupValueComparer;
|
||||
import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
|
||||
|
||||
/**
|
||||
* Implementation for the MATCH() Excel function.<p/>
|
||||
|
@ -93,7 +94,7 @@ public final class Match implements Function {
|
|||
|
||||
try {
|
||||
ValueEval lookupValue = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
|
||||
ValueEval[] lookupRange = evaluateLookupRange(args[1]);
|
||||
ValueVector lookupRange = evaluateLookupRange(args[1]);
|
||||
int index = findIndexOfValue(lookupValue, lookupRange, matchExact, findLargestLessThanOrEqual);
|
||||
return new NumberEval(index + 1); // +1 to convert to 1-based
|
||||
} catch (EvaluationException e) {
|
||||
|
@ -101,17 +102,38 @@ public final class Match implements Function {
|
|||
}
|
||||
}
|
||||
|
||||
private static ValueEval[] evaluateLookupRange(Eval eval) throws EvaluationException {
|
||||
private static final class SingleValueVector implements ValueVector {
|
||||
|
||||
private final ValueEval _value;
|
||||
|
||||
public SingleValueVector(ValueEval value) {
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public ValueEval getItem(int index) {
|
||||
if (index != 0) {
|
||||
throw new RuntimeException("Invalid index ("
|
||||
+ index + ") only zero is allowed");
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static ValueVector evaluateLookupRange(Eval eval) throws EvaluationException {
|
||||
if (eval instanceof RefEval) {
|
||||
RefEval re = (RefEval) eval;
|
||||
return new ValueEval[] { re.getInnerValueEval(), };
|
||||
return new SingleValueVector(re.getInnerValueEval());
|
||||
}
|
||||
if (eval instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) eval;
|
||||
if(!ae.isColumn() && !ae.isRow()) {
|
||||
ValueVector result = LookupUtils.createVector((AreaEval)eval);
|
||||
if (result == null) {
|
||||
throw new EvaluationException(ErrorEval.NA);
|
||||
}
|
||||
return ae.getValues();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Error handling for lookup_range arg is also unusual
|
||||
|
@ -160,14 +182,15 @@ public final class Match implements Function {
|
|||
/**
|
||||
* @return zero based index
|
||||
*/
|
||||
private static int findIndexOfValue(ValueEval lookupValue, ValueEval[] lookupRange,
|
||||
private static int findIndexOfValue(ValueEval lookupValue, ValueVector lookupRange,
|
||||
boolean matchExact, boolean findLargestLessThanOrEqual) throws EvaluationException {
|
||||
|
||||
LookupValueComparer lookupComparer = createLookupComparer(lookupValue, matchExact);
|
||||
|
||||
int size = lookupRange.getSize();
|
||||
if(matchExact) {
|
||||
for (int i = 0; i < lookupRange.length; i++) {
|
||||
if(lookupComparer.compareTo(lookupRange[i]).isEqual()) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if(lookupComparer.compareTo(lookupRange.getItem(i)).isEqual()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -176,8 +199,8 @@ public final class Match implements Function {
|
|||
|
||||
if(findLargestLessThanOrEqual) {
|
||||
// Note - backward iteration
|
||||
for (int i = lookupRange.length - 1; i>=0; i--) {
|
||||
CompareResult cmp = lookupComparer.compareTo(lookupRange[i]);
|
||||
for (int i = size - 1; i>=0; i--) {
|
||||
CompareResult cmp = lookupComparer.compareTo(lookupRange.getItem(i));
|
||||
if(cmp.isTypeMismatch()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -190,8 +213,8 @@ public final class Match implements Function {
|
|||
|
||||
// else - find smallest greater than or equal to
|
||||
// TODO - is binary search used for (match_type==+1) ?
|
||||
for (int i = 0; i<lookupRange.length; i++) {
|
||||
CompareResult cmp = lookupComparer.compareTo(lookupRange[i]);
|
||||
for (int i = 0; i<size; i++) {
|
||||
CompareResult cmp = lookupComparer.compareTo(lookupRange.getItem(i));
|
||||
if(cmp.isEqual()) {
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -42,40 +42,6 @@ import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
|
|||
*/
|
||||
public final class Vlookup implements Function {
|
||||
|
||||
private static final class ColumnVector implements ValueVector {
|
||||
|
||||
private final AreaEval _tableArray;
|
||||
private final int _size;
|
||||
private final int _columnAbsoluteIndex;
|
||||
private final int _firstRowAbsoluteIndex;
|
||||
|
||||
public ColumnVector(AreaEval tableArray, int columnIndex) {
|
||||
_columnAbsoluteIndex = tableArray.getFirstColumn() + columnIndex;
|
||||
if(!tableArray.containsColumn((short)_columnAbsoluteIndex)) {
|
||||
int lastColIx = tableArray.getLastColumn() - tableArray.getFirstColumn();
|
||||
throw new IllegalArgumentException("Specified column index (" + columnIndex
|
||||
+ ") is outside the allowed range (0.." + lastColIx + ")");
|
||||
}
|
||||
_tableArray = tableArray;
|
||||
_size = tableArray.getLastRow() - tableArray.getFirstRow() + 1;
|
||||
if(_size < 1) {
|
||||
throw new RuntimeException("bad table array size zero");
|
||||
}
|
||||
_firstRowAbsoluteIndex = tableArray.getFirstRow();
|
||||
}
|
||||
|
||||
public ValueEval getItem(int index) {
|
||||
if(index>_size) {
|
||||
throw new ArrayIndexOutOfBoundsException("Specified index (" + index
|
||||
+ ") is outside the allowed range (0.." + (_size-1) + ")");
|
||||
}
|
||||
return _tableArray.getValueAt(_firstRowAbsoluteIndex + index, (short)_columnAbsoluteIndex);
|
||||
}
|
||||
public int getSize() {
|
||||
return _size;
|
||||
}
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
Eval arg3 = null;
|
||||
switch(args.length) {
|
||||
|
@ -93,7 +59,7 @@ public final class Vlookup implements Function {
|
|||
ValueEval lookupValue = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
|
||||
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
|
||||
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
|
||||
int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, new ColumnVector(tableArray, 0), isRangeLookup);
|
||||
int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
|
||||
ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
|
||||
int colIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
|
||||
ValueVector resultCol = createResultColumnVector(tableArray, colIndex);
|
||||
|
@ -113,11 +79,9 @@ public final class Vlookup implements Function {
|
|||
if(colIndex < 0) {
|
||||
throw EvaluationException.invalidValue();
|
||||
}
|
||||
int nCols = tableArray.getLastColumn() - tableArray.getFirstColumn() + 1;
|
||||
|
||||
if(colIndex >= nCols) {
|
||||
if(colIndex >= tableArray.getWidth()) {
|
||||
throw EvaluationException.invalidRef();
|
||||
}
|
||||
return new ColumnVector(tableArray, colIndex);
|
||||
return LookupUtils.createColumnVector(tableArray, colIndex);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -32,7 +32,7 @@ import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
|||
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.functions.Countif.I_MatchPredicate;
|
||||
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
|
|
Loading…
Reference in New Issue