在数组中查找匹配或最接近的值

FMa*_*008 57 php arrays sorting search

对于给定的目标值,如何搜索和查找数组中最接近的值?

假设我有这个示例性数组:

array(0, 5, 10, 11, 12, 20)
Run Code Online (Sandbox Code Playgroud)

例如,当我用目标值0搜索时,函数应返回0; 当我用3搜索时,它将返回5; 当我用14搜索时,它将返回12.

Tim*_*per 102

将您要搜索的数字作为第一个参数传递,将数字数组传递给第二个参数:

function getClosest($search, $arr) {
   $closest = null;
   foreach ($arr as $item) {
      if ($closest === null || abs($search - $closest) > abs($item - $search)) {
         $closest = $item;
      }
   }
   return $closest;
}
Run Code Online (Sandbox Code Playgroud)

  • 必须佩服某人的大脑如何在4分钟内达到类似的功能 (4认同)
  • 这里要添加的一件事是,如果您想要比搜索值更接近,则需要按升序对数组进行排序,否则降序最接近搜索值. (2认同)
  • 很抱歉放弃这个旧的答案,但如果使用负数,我似乎有问题,任何建议? (2认同)

mar*_*rio 13

一种特殊的懒惰方法是让PHP按照搜索到的数字的距离对数组进行排序:

$num = 3;    
$array = array(0, 5, 10, 11, 12, 20);

foreach ($array as $i) {
    $smallest[$i] = abs($i - $num);
}
asort($smallest);
print key($smallest);
Run Code Online (Sandbox Code Playgroud)


Pet*_*ter 12

这是我为排序的大数组编写的高性能函数

对于具有20000个元素的数组,经过测试的主循环仅需要~20次迭代.

请注意数组必须排序(升序)!

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];
}
Run Code Online (Sandbox Code Playgroud)
  • ARRAY_NEAREST_DEFAULT 找到最近的元素
  • ARRAY_NEAREST_LOWER 找到最近的元素是LOWER
  • ARRAY_NEAREST_HIGHER 找到最接近的元素

用法:

$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);
Run Code Online (Sandbox Code Playgroud)

  • 我已经在[这个要点](https://gist.github.com/pepijnolivier/09435a18030419c4d15dbcf1058d536e)中使这个代码与PHP7兼容 (3认同)
  • 请注意,此功能在PHP7上无法立即使用,当缺少数组索引时会抛出错误。您必须添加适当的isset检查 (2认同)