Author: onealj
Date: Tue Jun 20 05:47:56 2017
New Revision: 1799302

URL: http://svn.apache.org/viewvc?rev=1799302&view=rev
Log:
bug 52063: support 2-argument LOOKUP(lookup_value, array) function in Excel

Modified:
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/Lookup.java
    poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/Lookup.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/Lookup.java?rev=1799302&r1=1799301&r2=1799302&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/Lookup.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/Lookup.java Tue Jun 
20 05:47:56 2017
@@ -6,7 +6,7 @@
    (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
+          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,
@@ -39,11 +39,42 @@ import org.apache.poi.ss.formula.TwoDEva
  */
 public final class Lookup extends Var2or3ArgFunction {
 
+       @Override
        public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, 
ValueEval arg0, ValueEval arg1) {
                // complex rules to choose lookupVector and resultVector from 
the single area ref
-               throw new RuntimeException("Two arg version of LOOKUP not 
supported yet");
+               
+               try {
+                       /*
+                       The array form of LOOKUP is very similar to the HLOOKUP 
and VLOOKUP functions. The difference is that HLOOKUP searches for the value of 
lookup_value in the first row, VLOOKUP searches in the first column, and LOOKUP 
searches according to the dimensions of array.
+                       If array covers an area that is wider than it is tall 
(more columns than rows), LOOKUP searches for the value of lookup_value in the 
first row.
+                       If an array is square or is taller than it is wide 
(more rows than columns), LOOKUP searches in the first column.
+                       With the HLOOKUP and VLOOKUP functions, you can index 
down or across, but LOOKUP always selects the last value in the row or column.
+                        */
+                       ValueEval lookupValue = 
OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+                       TwoDEval lookupArray = 
LookupUtils.resolveTableArrayArg(arg1);
+                       ValueVector lookupVector;
+                       ValueVector resultVector;
+       
+                       if (lookupArray.getWidth() > lookupArray.getHeight()) {
+                               // If array covers an area that is wider than 
it is tall (more columns than rows), LOOKUP searches for the value of 
lookup_value in the first row.
+                               lookupVector = 
createVector(lookupArray.getRow(0));
+                               resultVector = 
createVector(lookupArray.getRow(lookupArray.getHeight() - 1));
+                       } else {
+                               // If an array is square or is taller than it 
is wide (more rows than columns), LOOKUP searches in the first column.
+                               lookupVector = 
createVector(lookupArray.getColumn(0));
+                               resultVector = 
createVector(lookupArray.getColumn(lookupArray.getWidth() - 1));
+                       }
+                       // if a rectangular area reference was passed in as 
arg1, lookupVector and resultVector should be the same size
+                       assert (lookupVector.getSize() == 
resultVector.getSize());
+                       
+                       int index = LookupUtils.lookupIndexOfValue(lookupValue, 
lookupVector, true);
+                       return resultVector.getItem(index);
+               } catch (final EvaluationException e) {
+                       return e.getErrorEval();
+               }
        }
 
+       @Override
        public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, 
ValueEval arg0, ValueEval arg1,
                        ValueEval arg2) {
                try {

Modified: 
poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java?rev=1799302&r1=1799301&r2=1799302&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java 
(original)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java 
Tue Jun 20 05:47:56 2017
@@ -189,13 +189,68 @@ public final class TestFormulaBugs {
 
         wb.close();
        }
-
-    private void checkFormulaValue(Workbook wb, Cell cell, String formula, 
double expectedValue) {
-        cell.setCellFormula(formula);
+       
+       // bug 52063: LOOKUP(2-arg) and LOOKUP(3-arg)
+       // FIXME: This could be moved into LookupFunctionsTestCaseData.xls, 
which is tested by TestLookupFunctionsFromSpreadsheet.java
+       @Test
+       public void testLookupFormula() throws Exception {
+           Workbook wb = new HSSFWorkbook();
+           Sheet sheet = wb.createSheet("52063");
+           
+           // Note: Values in arrays are in ascending order since LOOKUP 
expects that in order to work properly
+           //         column
+           //         A B C
+           //       +-------
+           // row 1 | P Q R
+           // row 2 | X Y Z
+           Row row = sheet.createRow(0);
+           row.createCell(0).setCellValue("P");
+           row.createCell(1).setCellValue("Q");
+           row.createCell(2).setCellValue("R");
+           row = sheet.createRow(1);
+           row.createCell(0).setCellValue("X");
+           row.createCell(1).setCellValue("Y");
+           row.createCell(2).setCellValue("Z");
+           
+           Cell evalcell = sheet.createRow(2).createCell(0);
+           
+           //// ROW VECTORS
+           // lookup and result row are the same
+           checkFormulaValue(wb, evalcell, "LOOKUP(\"Q\", A1:C1)", "Q");
+           checkFormulaValue(wb, evalcell, "LOOKUP(\"R\", A1:C1)", "R");
+           checkFormulaValue(wb, evalcell, "LOOKUP(\"Q\", A1:C1, A1:C1)", "Q");
+           checkFormulaValue(wb, evalcell, "LOOKUP(\"R\", A1:C1, A1:C1)", "R");
+           
+           // lookup and result row are different
+           checkFormulaValue(wb, evalcell, "LOOKUP(\"Q\", A1:C2)", "Y");
+        checkFormulaValue(wb, evalcell, "LOOKUP(\"R\", A1:C2)", "Z");
+        checkFormulaValue(wb, evalcell, "LOOKUP(\"Q\", A1:C1, A2:C2)", "Y");
+           checkFormulaValue(wb, evalcell, "LOOKUP(\"R\", A1:C1, A2:C2)", "Z");
+           
+           //// COLUMN VECTORS
+        // lookup and result column are different
+        checkFormulaValue(wb, evalcell, "LOOKUP(\"P\", A1:B2)", "Q");
+        checkFormulaValue(wb, evalcell, "LOOKUP(\"X\", A1:A2, C1:C2)", "Z");
            
+           wb.close();
+       }
+       
+       private CellValue evaluateFormulaInCell(Workbook wb, Cell cell, String 
formula) {
+        cell.setCellFormula(formula);
+        
         FormulaEvaluator evaluator = 
wb.getCreationHelper().createFormulaEvaluator();
         CellValue value = evaluator.evaluate(cell);
         
+        return value;
+       }
+
+    private void checkFormulaValue(Workbook wb, Cell cell, String formula, 
double expectedValue) {
+        CellValue value = evaluateFormulaInCell(wb, cell, formula);
         assertEquals(expectedValue, value.getNumberValue(), 0.0001);
     }
+    
+    private void checkFormulaValue(Workbook wb, Cell cell, String formula, 
String expectedValue) {
+        CellValue value = evaluateFormulaInCell(wb, cell, formula);
+        assertEquals(expectedValue, value.getStringValue());
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to