Skip to content

Commit dfc74f8

Browse files
author
Mark Baker
committed
Feature: (amerov) - Implementation of the Excel HLOOKUP() function
1 parent 78c0348 commit dfc74f8

File tree

5 files changed

+110
-3
lines changed

5 files changed

+110
-3
lines changed

Classes/PHPExcel/Calculation.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ class PHPExcel_Calculation {
841841
'argumentCount' => '1,2'
842842
),
843843
'HLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
844-
'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
844+
'functionCall' => 'PHPExcel_Calculation_LookupRef::HLOOKUP',
845845
'argumentCount' => '3,4'
846846
),
847847
'HOUR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,

Classes/PHPExcel/Calculation/LookupRef.php

+65-1
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,8 @@ public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not
721721

722722
$rowNumber = $rowValue = False;
723723
foreach($lookup_array as $rowKey => $rowData) {
724-
if (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)) {
724+
if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) ||
725+
(!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)))) {
725726
break;
726727
}
727728
$rowNumber = $rowKey;
@@ -742,6 +743,69 @@ public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not
742743
} // function VLOOKUP()
743744

744745

746+
/**
747+
* HLOOKUP
748+
* The HLOOKUP function searches for value in the top-most row of lookup_array and returns the value in the same column based on the index_number.
749+
* @param lookup_value The value that you want to match in lookup_array
750+
* @param lookup_array The range of cells being searched
751+
* @param index_number The row number in table_array from which the matching value must be returned. The first row is 1.
752+
* @param not_exact_match Determines if you are looking for an exact match based on lookup_value.
753+
* @return mixed The value of the found cell
754+
*/
755+
public static function HLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match=true) {
756+
$lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value);
757+
$index_number = PHPExcel_Calculation_Functions::flattenSingleValue($index_number);
758+
$not_exact_match = PHPExcel_Calculation_Functions::flattenSingleValue($not_exact_match);
759+
760+
// index_number must be greater than or equal to 1
761+
if ($index_number < 1) {
762+
return PHPExcel_Calculation_Functions::VALUE();
763+
}
764+
765+
// index_number must be less than or equal to the number of columns in lookup_array
766+
if ((!is_array($lookup_array)) || (empty($lookup_array))) {
767+
return PHPExcel_Calculation_Functions::REF();
768+
} else {
769+
$f = array_keys($lookup_array);
770+
$firstRow = array_pop($f);
771+
if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array[$firstRow]))) {
772+
return PHPExcel_Calculation_Functions::REF();
773+
} else {
774+
$columnKeys = array_keys($lookup_array[$firstRow]);
775+
$firstkey = $f[0] - 1;
776+
$returnColumn = $firstkey + $index_number;
777+
$firstColumn = array_shift($f);
778+
}
779+
}
780+
781+
if (!$not_exact_match) {
782+
$firstRowH = asort($lookup_array[$firstColumn]);
783+
}
784+
785+
$rowNumber = $rowValue = False;
786+
foreach($lookup_array[$firstColumn] as $rowKey => $rowData) {
787+
if ((is_numeric($lookup_value) && is_numeric($rowData) && ($rowData > $lookup_value)) ||
788+
(!is_numeric($lookup_value) && !is_numeric($rowData) && (strtolower($rowData) > strtolower($lookup_value)))) {
789+
break;
790+
}
791+
$rowNumber = $rowKey;
792+
$rowValue = $rowData;
793+
}
794+
795+
if ($rowNumber !== false) {
796+
if ((!$not_exact_match) && ($rowValue != $lookup_value)) {
797+
// if an exact match is required, we have what we need to return an appropriate response
798+
return PHPExcel_Calculation_Functions::NA();
799+
} else {
800+
// otherwise return the appropriate value
801+
return $lookup_array[$returnColumn][$rowNumber];
802+
}
803+
}
804+
805+
return PHPExcel_Calculation_Functions::NA();
806+
} // function HLOOKUP()
807+
808+
745809
/**
746810
* LOOKUP
747811
* The LOOKUP function searches for value either from a one-row or one-column range or from an array.

changelog.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Fixed in develop branch for release v1.7.9a:
2727
- Bugfix: (MBaker) Work item 19830 - Undefined variable: fileHandle in CSV Reader
2828
- Bugfix: (MBaker) - Style error with merged cells in PDF Writer
2929
- Bugfix: (MBaker) - Problem with cloning worksheets
30-
30+
- Feature: (amerov) - Implementation of the Excel HLOOKUP() function
3131

3232
Fixed in develop branch for release v1.7.9:
3333
- Feature: (MBaker) Include charts option for HTML Writer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
4+
require_once 'testDataFileIterator.php';
5+
6+
class LookupRefTest extends PHPUnit_Framework_TestCase
7+
{
8+
9+
public function setUp()
10+
{
11+
if (!defined('PHPEXCEL_ROOT'))
12+
{
13+
define('PHPEXCEL_ROOT', APPLICATION_PATH . '/');
14+
}
15+
require_once(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
16+
}
17+
18+
/**
19+
* @dataProvider providerHLOOKUP
20+
*/
21+
public function testHLOOKUP()
22+
{
23+
$args = func_get_args();
24+
$expectedResult = array_pop($args);
25+
$result = call_user_func_array(array('PHPExcel_Calculation_LookupRef','HLOOKUP'),$args);
26+
$this->assertEquals($expectedResult, $result);
27+
}
28+
29+
public function providerHLOOKUP()
30+
{
31+
return new testDataFileIterator('rawTestData/Calculation/LookupRef/HLOOKUP.data');
32+
}
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
10251, {"Order ID"|10247|10249|10250|10251|10252|10253;"Unit Price"|14.00|18.60|7.70|16.80|16.80|64.80;"Quantity"|12|9|10|6|20|40}, 2, FALSE, 16.8
2+
10251, {"Order ID"|10247|10249|10250|10251|10252|10253;"Unit Price"|14.00|18.60|7.70|16.80|16.80|64.80;"Quantity"|12|9|10|6|20|40}, 3, FALSE, 6.0
3+
10248, {"Order ID"|10247|10249|10250|10251|10252|10253;"Unit Price"|14.00|18.60|7.70|16.80|16.80|64.80;"Quantity"|12|9|10|6|20|40}, 2, FALSE, "#N/A"
4+
10248, {"Order ID"|10247|10249|10250|10251|10252|10253;"Unit Price"|14.00|18.60|7.70|16.80|16.80|64.80;"Quantity"|12|9|10|6|20|40}, 2, TRUE, 14.0
5+
"Axles", {"Axles"|"Bearings"|"Bolts";4|4|9;5|7|10;6|8|11}, 2, TRUE, 4
6+
"Bearings", {"Axles"|"Bearings"|"Bolts";4|4|9;5|7|10;6|8|11}, 3, FALSE, 7
7+
"B", {"Axles"|"Bearings"|"Bolts";4|4|9;5|7|10;6|8|11}, 3, TRUE, 5
8+
"Bolts", {"Axles"|"Bearings"|"Bolts";4|4|9;5|7|10;6|8|11}, 4, 11
9+
3, {1|2|3;"a"|"b"|"c";"d"|"e"|"f"}, 2, TRUE, "c"

0 commit comments

Comments
 (0)