Exact match in VLOOKUP now returns first match
It was inconsistent with spreadsheet software before. Closes #809
This commit is contained in:
parent
db2621c4fe
commit
294ba58dde
|
@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
||||||
- Improve XLSX parsing speed if no readFilter is applied - [#772](https://github.com/PHPOffice/PhpSpreadsheet/issues/772)
|
- Improve XLSX parsing speed if no readFilter is applied - [#772](https://github.com/PHPOffice/PhpSpreadsheet/issues/772)
|
||||||
- Fix column names if read filter calls in XLSX reader skip columns - [#777](https://github.com/PHPOffice/PhpSpreadsheet/pull/777)
|
- Fix column names if read filter calls in XLSX reader skip columns - [#777](https://github.com/PHPOffice/PhpSpreadsheet/pull/777)
|
||||||
- Fix LOOKUP function which was breaking on edge cases - [#796](https://github.com/PHPOffice/PhpSpreadsheet/issues/796)
|
- Fix LOOKUP function which was breaking on edge cases - [#796](https://github.com/PHPOffice/PhpSpreadsheet/issues/796)
|
||||||
|
- Fix VLOOKUP with exact matches
|
||||||
|
|
||||||
## [1.5.2] - 2018-11-25
|
## [1.5.2] - 2018-11-25
|
||||||
|
|
||||||
|
|
|
@ -421,7 +421,7 @@ class LookupRef
|
||||||
* @param mixed $index_num Specifies which value argument is selected.
|
* @param mixed $index_num Specifies which value argument is selected.
|
||||||
* Index_num must be a number between 1 and 254, or a formula or reference to a cell containing a number
|
* Index_num must be a number between 1 and 254, or a formula or reference to a cell containing a number
|
||||||
* between 1 and 254.
|
* between 1 and 254.
|
||||||
* @param mixed $value1... Value1 is required, subsequent values are optional.
|
* @param mixed $value1 ... Value1 is required, subsequent values are optional.
|
||||||
* Between 1 to 254 value arguments from which CHOOSE selects a value or an action to perform based on
|
* Between 1 to 254 value arguments from which CHOOSE selects a value or an action to perform based on
|
||||||
* index_num. The arguments can be numbers, cell references, defined names, formulas, functions, or
|
* index_num. The arguments can be numbers, cell references, defined names, formulas, functions, or
|
||||||
* text.
|
* text.
|
||||||
|
@ -709,6 +709,7 @@ class LookupRef
|
||||||
|
|
||||||
$rowNumber = $rowValue = false;
|
$rowNumber = $rowValue = false;
|
||||||
foreach ($lookup_array as $rowKey => $rowData) {
|
foreach ($lookup_array as $rowKey => $rowData) {
|
||||||
|
// break if we have passed possible keys
|
||||||
if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) ||
|
if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) ||
|
||||||
(!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)))) {
|
(!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)))) {
|
||||||
break;
|
break;
|
||||||
|
@ -716,17 +717,25 @@ class LookupRef
|
||||||
// remember the last key, but only if datatypes match
|
// remember the last key, but only if datatypes match
|
||||||
if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn])) ||
|
if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn])) ||
|
||||||
(!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]))) {
|
(!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]))) {
|
||||||
|
if ($not_exact_match) {
|
||||||
|
$rowNumber = $rowKey;
|
||||||
|
$rowValue = $rowData[$firstColumn];
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} elseif ((strtolower($rowData[$firstColumn]) == strtolower($lookup_value))
|
||||||
|
// Spreadsheets software returns first exact match,
|
||||||
|
// we have sorted and we might have broken key orders
|
||||||
|
// we want the first one (by its initial index)
|
||||||
|
&& (($rowNumber == false) || ($rowKey < $rowNumber))
|
||||||
|
) {
|
||||||
$rowNumber = $rowKey;
|
$rowNumber = $rowKey;
|
||||||
$rowValue = $rowData[$firstColumn];
|
$rowValue = $rowData[$firstColumn];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($rowNumber !== false) {
|
if ($rowNumber !== false) {
|
||||||
if ((!$not_exact_match) && ($rowValue != $lookup_value)) {
|
// return the appropriate value
|
||||||
// if an exact match is required, we have what we need to return an appropriate response
|
|
||||||
return Functions::NA();
|
|
||||||
}
|
|
||||||
// otherwise return the appropriate value
|
|
||||||
return $lookup_array[$rowNumber][$returnColumn];
|
return $lookup_array[$rowNumber][$returnColumn];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,29 +773,35 @@ class LookupRef
|
||||||
if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array))) {
|
if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array))) {
|
||||||
return Functions::REF();
|
return Functions::REF();
|
||||||
}
|
}
|
||||||
$columnKeys = array_keys($lookup_array[$firstRow]);
|
|
||||||
$firstkey = $f[0] - 1;
|
$firstkey = $f[0] - 1;
|
||||||
$returnColumn = $firstkey + $index_number;
|
$returnColumn = $firstkey + $index_number;
|
||||||
$firstColumn = array_shift($f);
|
$firstColumn = array_shift($f);
|
||||||
|
$rowNumber = null;
|
||||||
if (!$not_exact_match) {
|
|
||||||
$firstRowH = asort($lookup_array[$firstColumn]);
|
|
||||||
}
|
|
||||||
$rowNumber = $rowValue = false;
|
|
||||||
foreach ($lookup_array[$firstColumn] as $rowKey => $rowData) {
|
foreach ($lookup_array[$firstColumn] as $rowKey => $rowData) {
|
||||||
if ((is_numeric($lookup_value) && is_numeric($rowData) && ($rowData > $lookup_value)) ||
|
// break if we have passed possible keys
|
||||||
(!is_numeric($lookup_value) && !is_numeric($rowData) && (strtolower($rowData) > strtolower($lookup_value)))) {
|
$bothNumeric = is_numeric($lookup_value) && is_numeric($rowData);
|
||||||
|
$bothNotNumeric = !is_numeric($lookup_value) && !is_numeric($rowData);
|
||||||
|
if (($bothNumeric && $rowData > $lookup_value) ||
|
||||||
|
($bothNotNumeric && strtolower($rowData) > strtolower($lookup_value))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember the last key, but only if datatypes match (as in VLOOKUP)
|
||||||
|
if ($bothNumeric || $bothNotNumeric) {
|
||||||
|
if ($not_exact_match) {
|
||||||
$rowNumber = $rowKey;
|
$rowNumber = $rowKey;
|
||||||
$rowValue = $rowData;
|
|
||||||
|
continue;
|
||||||
|
} elseif (strtolower($rowData) === strtolower($lookup_value)
|
||||||
|
&& ($rowNumber === null || $rowKey < $rowNumber)
|
||||||
|
) {
|
||||||
|
$rowNumber = $rowKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rowNumber !== false) {
|
if ($rowNumber !== null) {
|
||||||
if ((!$not_exact_match) && ($rowValue != $lookup_value)) {
|
|
||||||
// if an exact match is required, we have what we need to return an appropriate response
|
|
||||||
return Functions::NA();
|
|
||||||
}
|
|
||||||
// otherwise return the appropriate value
|
// otherwise return the appropriate value
|
||||||
return $lookup_array[$returnColumn][$rowNumber];
|
return $lookup_array[$returnColumn][$rowNumber];
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,4 +275,14 @@ return [
|
||||||
2,
|
2,
|
||||||
true,
|
true,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
5,
|
||||||
|
'x',
|
||||||
|
[
|
||||||
|
['Selection column', '0', '0', '0', '0', 'x', 'x', 'x', 'x', 'x'],
|
||||||
|
['Value to retrieve', 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
],
|
||||||
|
2,
|
||||||
|
false
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|
|
@ -291,4 +291,25 @@ return [
|
||||||
2,
|
2,
|
||||||
true,
|
true,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
5,
|
||||||
|
'x',
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'Selection column',
|
||||||
|
'Value to retrieve',
|
||||||
|
],
|
||||||
|
['0', 1],
|
||||||
|
['0', 2],
|
||||||
|
['0', 3],
|
||||||
|
['0', 4],
|
||||||
|
['x', 5],
|
||||||
|
['x', 6],
|
||||||
|
['x', 7],
|
||||||
|
['x', 8],
|
||||||
|
['x', 9],
|
||||||
|
],
|
||||||
|
2,
|
||||||
|
false
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue