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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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
	
	Block a user