Encuentre un valor coincidente o más cercano en una matriz
¿Cómo puedo buscar y encontrar, para un valor objetivo determinado, el valor más cercano en una matriz?
Digamos que tengo esta matriz ejemplar:
array(0, 5, 10, 11, 12, 20)
Por ejemplo, cuando busco con el valor objetivo 0, la función devolverá 0; cuando busco con 3, me devolverá 5; cuando busco con 14, devolverá 12.
Aceptado
Pase el número que está buscando como primer parámetro y la matriz de números como segundo:
function getClosest($search, $arr) {
$closest = null;
foreach ($arr as $item) {
if ($closest === null || abs($search - $closest) > abs($item - $search)) {
$closest = $item;
}
}
return $closest;
}
Un enfoque perezoso particular es hacer que PHP ordene la matriz por la distancia al número buscado:
$num = 3;
$array = array(0, 5, 10, 11, 12, 20);
$smallest = [];
foreach ($array as $i) {
$smallest[$i] = abs($i - $num);
}
asort($smallest);
print key($smallest);
Esta es una función de alto rendimiento que escribí para matrices grandes ordenadas.
Probado, el bucle principal necesita solo ~20 iteraciones para una matriz con 20000 elementos.
¡Tenga en cuenta que la matriz debe estar ordenada (ascendente)!
define('ARRAY_NEAREST_DEFAULT', 0);
define('ARRAY_NEAREST_LOWER', 1);
define('ARRAY_NEAREST_HIGHER', 2);
/**
* Finds nearest value in numeric array. Can be used in loops.
* Array needs to be non-assocative and sorted.
*
* @param array $array
* @param int $value
* @param int $method ARRAY_NEAREST_DEFAULT|ARRAY_NEAREST_LOWER|ARRAY_NEAREST_HIGHER
* @return int
*/
function array_numeric_sorted_nearest($array, $value, $method = ARRAY_NEAREST_DEFAULT) {
$count = count($array);
if($count == 0) {
return null;
}
$div_step = 2;
$index = ceil($count / $div_step);
$best_index = null;
$best_score = null;
$direction = null;
$indexes_checked = Array();
while(true) {
if(isset($indexes_checked[$index])) {
break ;
}
$curr_key = $array[$index];
if($curr_key === null) {
break ;
}
$indexes_checked[$index] = true;
// perfect match, nothing else to do
if($curr_key == $value) {
return $curr_key;
}
$prev_key = $array[$index - 1];
$next_key = $array[$index + 1];
switch($method) {
default:
case ARRAY_NEAREST_DEFAULT:
$curr_score = abs($curr_key - $value);
$prev_score = $prev_key !== null ? abs($prev_key - $value) : null;
$next_score = $next_key !== null ? abs($next_key - $value) : null;
if($prev_score === null) {
$direction = 1;
}else if ($next_score === null) {
break 2;
}else{
$direction = $next_score < $prev_score ? 1 : -1;
}
break;
case ARRAY_NEAREST_LOWER:
$curr_score = $curr_key - $value;
if($curr_score > 0) {
$curr_score = null;
}else{
$curr_score = abs($curr_score);
}
if($curr_score === null) {
$direction = -1;
}else{
$direction = 1;
}
break;
case ARRAY_NEAREST_HIGHER:
$curr_score = $curr_key - $value;
if($curr_score < 0) {
$curr_score = null;
}
if($curr_score === null) {
$direction = 1;
}else{
$direction = -1;
}
break;
}
if(($curr_score !== null) && ($curr_score < $best_score) || ($best_score === null)) {
$best_index = $index;
$best_score = $curr_score;
}
$div_step *= 2;
$index += $direction * ceil($count / $div_step);
}
return $array[$best_index];
}
ARRAY_NEAREST_DEFAULT
encuentra el elemento más cercanoARRAY_NEAREST_LOWER
encuentra el elemento más cercano que es INFERIORARRAY_NEAREST_HIGHER
encuentra el elemento más cercano que es MÁS ALTO
Uso:
$test = Array(5,2,8,3,9,12,20,...,52100,52460,62000);
// sort an array and use array_numeric_sorted_nearest
// for multiple searches.
// for every iteration it start from half of chunk where
// first chunk is whole array
// function doesn't work with unosrted arrays, and it's much
// faster than other solutions here for sorted arrays
sort($test);
$nearest = array_numeric_sorted_nearest($test, 8256);
$nearest = array_numeric_sorted_nearest($test, 3433);
$nearest = array_numeric_sorted_nearest($test, 1100);
$nearest = array_numeric_sorted_nearest($test, 700);