The Adaptive Calculation Engine ACE4J XLOOKUP function's behavior and syntax are almost identical to the Excel XLOOKUP function. Some insignificant differences are related to their platform differences (Java vs. Excel), while others constitute advantages of the ACE4J XLOOKUP function such as its ability to perform a suitable binary search even if lookup_array elements are not sorted.
Syntax
lookup_value Required.
The lookup value.
lookup_array_name Required.
The name of a single row or single column TableArray object in which the XLOOKUP will search for the lookup_value. TableArray objects are placed in the HashMap and retrieved by their names during the formula evaluation.
return_array_name Required.
The name of a TableArray object from which the XLOOKUP will retrieve the return value.
[if_not_found] Optional.
Where a valid match is not found, the formula field getDisplayValue() method returns the [if_not_found] text you supply. If a valid match is not found, and [if_not_found] is missing, #N/A will be returned.
[match_mode] Optional.
Specify the match type:
If the match_mode is 2 and the lookup_value is a text string, you can use the wildcard characters − the question mark (?) and asterisk (*) in the lookup_value argument. A question mark matches any single character; an asterisk matches any sequence of characters. If you want to find an actual question mark or asterisk, type a tilde (~) before the character.
[seach_mode] Optional. Specify the search mode to use:
The lookup_array elements are not required to be sorted for any seach_mode value.
The XLOOKUP function searches a lookup_array and returns an item from a return_array, which corresponds to the first match it finds. If a match does not exist, XLOOKUP can return the closest (approximate) match. If XLOOKUP returns an array of values for the entire column or row, it must be used as an argument of one of the following functions: XLOOKUP, MAX, MIN, SUM, AVERAGE, MEDIAN, MODE, COUNT, COUNTA, COUNTBLANK, CONCATENATE, and CONCAT or an error will be produced. This is the Adaptive Calculation Engine implementation of Excel XLOOKUP function. In this XLOOKUP implementation the optional search_mode parameter has a slightly different set of allowed values than the original one. A TableArray object used as the lookup_array is automatically sorted in the applicable order and a binary search is applied whenever possible.
The below examples were constructed based on the XLOOKUP examples published on the Microsoft Office Support site.
The first example uses a basic 3-parameter version of XLOOKUP to look up a car make, then returns its model. It includes lookup_value ("VOLVO"), lookup_array (range C5:C12), and return_array (range D5:D12) arguments. The basic 3-parameter XLOOKUP defaults to an exact match:
The Adaptive Calculation Engine version of this example uses the two-dimensional array lookupTable corresponding to the above shown range of cells B4:D12. Using this lookupTable it creates the TableArray object car corresponding to the range of cells C5:C12, and the TableArray object model corresponding to the range of cells D5:D12.
Both TableArray objects are then placed in the tableArrays HashMap with keys named "car_make" and "model." The below ACE4J XLOOKUP formula my_formula is equivalent to the XLOOKUP (B2,C5:C12,D5:D12) formula in this example:
import com.crystalprism.ce.formula.HybridFormulaEvaluator; import com.crystalprism.ce.usermodel.*; public class XlookupExample1 { private static TableArray getTableArray(Object[][] lookupTable, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) { return (new TableArray(lookupTable, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex)); } public static void main(String[] args) { Object[][] lookupTable = {{"Country", "Car Make", "Model"}, {"France", "PEUGEOT", "1007"}, {"Germany", "BMW", "X3"}, {"Italy", "ALFA ROMEO", "GIULIA"}, {"Japan", "TOYOTA", "CAMRY"}, {"South Korea", "KIA", "SELTOS"}, {"Sweden", "VOLVO", "V90"}, {"UK", "LAND ROVER", "DEFENDER"}, {"United States", "FORD", "RANGER"}}; // Car Make column without its title TableArray carMake = getTableArray(lookupTable, 1, 1, lookupTable.length - 1, 1); // Model column without its title TableArray model = getTableArray(lookupTable, 1, lookupTable[0].length - 1, lookupTable.length - 1, lookupTable[0].length - 1); CalculationContext calculationContext = new CalculationContext("XlookupExample1"); InputField car = new InputField(ComputeFieldType.ALPHANUMERIC, "VOLVO"); String myFormulaText = "XLOOKUP(car, \"Car_Make\", \"Model\")"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.ALPHANUMERIC, myFormulaText); // ComputeFields calculationContext.put("car", car); calculationContext.put("model_formula", myFormulaField); // TableArrays calculationContext.put("Car_Make", carMake); calculationContext.put("Model", model); HybridFormulaEvaluator.evaluateFormula("model_formula", calculationContext); System.out.printf("Car make: %s \nModel: %s", car.getDisplayValue(), myFormulaField.getDisplayValue()); } } Car make: VOLVO Model: V90
The second example is looking up movie information based on its budget. Unlike VLOOKUP, XLOOKUP is able to return an array with multiple items, which allows a single formula to return both genre and title from cells B5:C12:
The Adaptive Calculation Engine version of this example uses the two-dimensional array lookupTable corresponding to the above shown range of cells B4:D12. (lookupTable uses one additional column with spaces for demonstration purposes). Using this lookupTable it creates the TableArray object budget corresponding to the range of cells D5:D12, and the TableArray object genreTitle corresponding to the range of cells B5:C12. Both TableArray objects are then placed in the tableArrays HashMap with keys named "budget" and "genre_and_title." The ACE4J XLOOKUP function in the below formula my_formula is equivalent to the XLOOKUP( B2,D5:D12,B5:C12) formula in this example. The movie genre and title returned by ACE4J XLOOKUP will be consumed by the CONCATENATE function added for demonstration purposes:
import com.crystalprism.ce.formula.HybridFormulaEvaluator; import com.crystalprism.ce.usermodel.*; public class XlookupExample2 { private static TableArray getTableArray(Object[][] lookupTable, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) { return (new TableArray(lookupTable, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex)); } public static void main(String[] args) { Object[][] lookupTable = {{"Genre", " ", "Title", "Budget"}, {"Comedy", " ", "My Spy", 18000000.00}, {"Grime", " ", "The host", 40000000.00}, {"Drama", " ", "Little Women", 40000000.00}, {"Sci-Fi", " ", "Ad Astra", 80000000.00}, {"Adventure", " ", "The Call of the Wild", 109000000.00}, {"Animation", " ", "Missing Link", 150000000.00}, {"Action", " ", "No Time to Die", 250000000.00}, {"Family", " ", "Lion King", 260000000.00}}; // Budget column without its title TableArray budget = getTableArray(lookupTable, 1, lookupTable[0].length - 1, lookupTable.length - 1, lookupTable[0].length - 1); // Genre and Title columns without their titles and empty column in between TableArray genreTitle = getTableArray(lookupTable, 1, 0, lookupTable.length - 1, 2); CalculationContext calculationContext = new CalculationContext("XlookupExample2"); InputField movieBudget = new InputField(ComputeFieldType.NUMERIC, 80000000.00); String myFormulaText = "CONCATENATE(XLOOKUP(movie_budget, \"Budget\", \"Genre_and_Title\"))"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.ALPHANUMERIC, myFormulaText);; // ComputeFields calculationContext.put("movie_budget", movieBudget); calculationContext.put("my_formula", myFormulaField); // TableArrays calculationContext.put("Budget", budget); calculationContext.put("Genre_and_Title", genreTitle); HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext); System.out.println(myFormulaField.getDisplayValue()); } } Sci-Fi Ad Astra
The third example adds the if_not_found parameter to the formula in the previous example:
import com.crystalprism.ce.formula.HybridFormulaEvaluator; import com.crystalprism.ce.usermodel.*; public class XlookupExample3 { private static TableArray getTableArray(Object[][] lookupTable, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) { return (new TableArray(lookupTable, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex)); } public static void main(String[] args) { Object[][] lookupTable = {{"Genre", " ", "Title", "Budget"}, {"Comedy", " ", "My Spy", 18000000.00}, {"Grime", " ", "The host", 40000000.00}, {"Drama", " ", "Little Women", 40000000.00}, {"Sci-Fi", " ", "Ad Astra", 80000000.00}, {"Adventure", " ", "The Call of the Wild", 109000000.00}, {"Animation", " ", "Missing Link", 150000000.00}, {"Action", " ", "No Time to Die", 250000000.00}, {"Family", " ", "Lion King", 260000000.00}}; // Budget column without its title TableArray budget = getTableArray(lookupTable, 1, lookupTable[0].length - 1, lookupTable.length - 1, lookupTable[0].length - 1); // Genre and Title columns without their titles and empty column in between TableArray genreTitle = getTableArray(lookupTable, 1, 0, lookupTable.length - 1, 2); CalculationContext calculationContext = new CalculationContext("XlookupExample3"); InputField movieBudget = new InputField(ComputeFieldType.NUMERIC, 90000000.00); String myFormulaText = "CONCATENATE(XLOOKUP(movie_budget, \"budget\", \"genre_and_title\"," + " \"movie not found\"))"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.ALPHANUMERIC, myFormulaText); // ComputeFields calculationContext.put("movie_budget", movieBudget); calculationContext.put("my_formula", myFormulaField); // TableArrays calculationContext.put("Budget", budget); calculationContext.put("Genre_and_Title", genreTitle); HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext); System.out.println("90 million budget " + myFormulaField.getDisplayValue()); } } 90 million budget movie not found
The fourth example looks in column D for the budget entered in cell B2, and finds a matching title in column C. It sets the if_not_found argument to return a "title not found" text if nothing is found. The match_mode argument is set to 1, which means the function will look for an exact match, and if it can't find one, it will return the next larger item. Finally, the search_mode argument is set to 1, which means the function will search from the first item to the last.
The Adaptive Calculation Engine version of this example uses the two-dimensional array lookupTable corresponding to the above shown range of cells B4:D12. Using this lookupTable it creates the TableArray object budget corresponding to the range of cells D5:D12, and the TableArray object title corresponding to the range of cells C5:C12. Both TableArray objects are then placed in the tableArrays HashMap with keys named "budget" and "title." The if_not_found argument is set to "Title not found" and match_mode argument is set to 1, exactly as it is done in the Excel XLOOKUP formula of this example. The search_mode argument is also set to 1. This combination of match_mode and search_mode arguments allows the below XLOOKUP expression to successfully perform a suitable binary search. The ACE4J XLOOKUP is capable of performing such a search even if the "budget" column is not sorted. The below ACE4J XLOOKUP formula is equivalent to the XLOOKUP( B2,D5:D12,C5:C12, "Title not found",1,1) formula in this example:
import com.crystalprism.ce.formula.HybridFormulaEvaluator; import com.crystalprism.ce.usermodel.*; public class XlookupExample4 { private static TableArray getTableArray(Object[][] lookupTable, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) { return (new TableArray(lookupTable, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex)); } public static void main(String[] args) { Object[][] lookupTable = {{"Genre", "Title", "Budget"}, {"Comedy", "My Spy", 18000000.00}, {"Grime", "The host", 40000000.00}, {"Drama", "Little Women", 40000000.00}, {"Sci-Fi", "Ad Astra", 80000000.00}, {"Adventure", "The Call of the Wild", 109000000.00}, {"Animation", "Missing Link", 150000000.00}, {"Action", "No Time to Die", 250000000.00}, {"Family", "Lion King", 260000000.00}}; // Budget column without its title TableArray budget = getTableArray(lookupTable, 1, lookupTable[0].length - 1, lookupTable.length - 1, lookupTable[0].length - 1); // Title column without its title TableArray title = getTableArray(lookupTable, 1, 1, lookupTable.length - 1, 1); CalculationContext calculationContext = new CalculationContext("XlookupExample4"); InputField movieBudget = new InputField(ComputeFieldType.NUMERIC, 130000000.00); String myFormulaText = "XLOOKUP(movie_budget, \"Budget\", \"Title\", \"title not found\", 1, 1)"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.ALPHANUMERIC, myFormulaText);; // ComputeFields calculationContext.put("movie_budget", movieBudget); calculationContext.put("my_formula", myFormulaField); // TableArrays calculationContext.put("Budget", budget); calculationContext.put("Title", title); HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext); System.out.println(myFormulaField.getDisplayValue()); } } Missing Link
The fifth example uses a nested XLOOKUP function to perform both a vertical and horizontal match. In this case, it will first look for Wimbledon Grand Slam tournament in row 4, then look for the player named Pete Sampras in column B, and return the value at the intersection of the two. This is similar to using the INDEX and MATCH functions in conjunction.
The Adaptive Calculation Engine version of this example uses the two-dimensional array lookupTable corresponding to the above shown range of cells B4:G11. Using this lookupTable it creates the TableArray object tournament corresponding to the range of cells C4:F4, the TableArray object numberOfTimes corresponding to the range of cells C5:F11, and the TableArray object tennisPlayer corresponding to the range of cells B5:B11. These TableArray objects are placed in the tableArrays HashMap with keys named "tournament," "number_of_timest," and "tennis_player." The inner XLOOKUP function returns the Wimbledon column, which will be used as the return_array of the outer XLOOKUP function.
The below ACE4J XLOOKUP formula is equivalent to the XLOOKUP (C2,B5:B11,XLOOKUP(B2,C4:F4,C5:F11)) formula in this example:
import com.crystalprism.ce.formula.HybridFormulaEvaluator; import com.crystalprism.ce.usermodel.*; public class XlookupExample5 { private static TableArray getTableArray(Object[][] lookupTable, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) { return (new TableArray(lookupTable, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex)); } public static void main(String[] args) { Object[][] lookupTable = {{"Tennis Player", "Australian Open", "Rolan Garros", "Wimbledon", "US Open", "Total"}, {"Roger Federer", 6, 1, 8, 5, 20}, {"Rafael Nadal", 1, 12, 2, 4, 19}, {"Novak Djokovic", 8, 1, 5, 3, 17}, {"Pete Sampras", 2, 0, 7, 5, 14}, {"Roy Emerson", 6, 2, 2, 2, 12}, {"Bjorn Borg", 0, 6, 5, 0, 11}, {"Rodney Laver", 3, 2, 4, 2, 11}}; // Tournaments : Australian Open, Rolan Garros, Wimbledon, US Open TableArray tournaments = getTableArray(lookupTable, 0, 1, 0,4); // Number of times each player won Grand Slam tournaments TableArray numberOfTimes = getTableArray(lookupTable, 1, 1, lookupTable.length - 1,4); // Tennis Player column without its title TableArray tennisPlayer = getTableArray(lookupTable, 1, 0, lookupTable.length - 1,0); CalculationContext calculationContext = new CalculationContext("XlookupExample5"); InputField selectedGrandSlam = new InputField(ComputeFieldType.ALPHANUMERIC, "Wimbledon"); InputField selectedPlayer = new InputField(ComputeFieldType.ALPHANUMERIC, "Pete Sampras"); String myFormulaText = "XLOOKUP(selected_player, \"Tennis_Player\", XLOOKUP(selected_grand_slam, " + "\"Tournaments\", \"Number_of_Times\"))"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText);; // ComputeFields calculationContext.put("selected_grand_slam", selectedGrandSlam); calculationContext.put("selected_player", selectedPlayer); calculationContext.put("my_formula", myFormulaField); // TableArrays calculationContext.put("Tournaments", tournaments); calculationContext.put("Number_of_Times", numberOfTimes); calculationContext.put("Tennis_Player", tennisPlayer); HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext); System.out.println("Pete Sampras won Wimbledon " + myFormulaField.getDisplayValue() + " times"); } } Pete Sampras won Wimbledon 7 times