Ближайшее значение из массива

У меня есть следующий массив:

array(0, 5, 10, 11, 12, 20) 

Как найти «ближайшее» значение иглы? Было бы предпочтительнее, если бы игла могла быть параметром.

Примеры:

  • Поиск: 0, возврат 0
  • Поиск: 2, возврат 0
  • Поиск: 3, возвращение 5
  • Поиск: 4, возвращение 5
  • Поиск: 5, возвращение 5
  • Поиск: 11, возвращение 11
  • Поиск: 19, возвращение 20
  • Поиск: 20, возвращение 20

Related of "Ближайшее значение из массива"

Передайте номер, который вы ищете, как первый параметр, а массив чисел – второй:

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

Особый ленивый подход заключается в том, что 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); 

Это высокопроизводительная функция, которую я написал для отсортированных больших массивов

Протестированный основной цикл требует всего ~ 20 итераций для массива с 20000 элементами.

Пожалуйста, настройте массив, чтобы сортировать (по возрастанию)!

 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 находит ближайший элемент
  • 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); 
 <?php $arr = array(0, 5, 10, 11, 12, 20); function getNearest($arr,$var){ usort($arr, function($a,$b) use ($var){ return abs($a - $var) - abs($b - $var); }); return array_shift($arr); } ?> 

Вы можете просто использовать array_search для этого, он возвращает один единственный ключ, если в массиве есть много экземпляров вашего поиска, он вернет первый найденный.

Цитата из PHP :

Если игла найдена в стоге сена более одного раза, возвращается первая совпадающая клавиша. Чтобы вернуть ключи для всех совпадающих значений, используйте параметр array_keys () с необязательным параметром search_value.

Пример использования:

 if(false !== ($index = array_search(12,array(0, 5, 10, 11, 12, 20)))) { echo $index; //5 } 

Обновить:

 function findNearest($number,$Array) { //First check if we have an exact number if(false !== ($exact = array_search($number,$Array))) { return $Array[$exact]; } //Sort the array sort($Array); //make sure our search is greater then the smallest value if ($number < $Array[0] ) { return $Array[0]; } $closest = $Array[0]; //Set the closest to the lowest number to start foreach($Array as $value) { if(abs($number - $closest) > abs($value - $number)) { $closest = $value; } } return $closest; } 

Реализация Тима будет сокращать его большую часть времени. Тем не менее, для обеспечения осторожности вы можете отсортировать список до итерации и разбить поиск, когда следующее различие больше последнего.

 <?php function getIndexOfClosestValue ($needle, $haystack) { if (count($haystack) === 1) { return $haystack[0]; } sort($haystack); $closest_value_index = 0; $last_closest_value_index = null; foreach ($haystack as $i => $item) { if (abs($needle - $haystack[$closest_value_index]) > abs($item - $needle)) { $closest_value_index = $i; } if ($closest_value_index === $last_closest_value_index) { break; } } return $closest_value_index; } function getClosestValue ($needle, $haystack) { return $haystack[getIndexOfClosestValue($needle, $haystack)]; } // Test $needles = [0, 2, 3, 4, 5, 11, 19, 20]; $haystack = [0, 5, 10, 11, 12, 20]; $expectation = [0, 0, 1, 1, 1, 3, 5, 5]; foreach ($needles as $i => $needle) { var_dump( getIndexOfClosestValue($needle, $haystack) === $expectation[$i] ); } 

Чтобы найти ближайшее значение в массиве объектов, вы можете использовать этот адаптированный код из ответа Тима Купера .

 <?php // create array of ten objects with random values $images = array(); for ($i = 0; $i < 10; $i++) $images[ $i ] = (object)array( 'width' => rand(100, 1000) ); // print array print_r($images); // adapted function from Tim Copper's solution // https://stackoverflow.com/a/5464961/496176 function closest($array, $member, $number) { $arr = array(); foreach ($array as $key => $value) $arr[$key] = $value->$member; $closest = null; foreach ($arr as $item) if ($closest === null || abs($number - $closest) > abs($item - $number)) $closest = $item; $key = array_search($closest, $arr); return $array[$key]; } // object needed $needed_object = closest($images, 'width', 320); // print result print_r($needed_object); ?> 
 function closestnumber($number, $candidates) { $last = null; foreach ($candidates as $cand) { if ($cand < $number) { $last = $cand; } else if ($cand == $number) { return $number; } else if ($cand > $number) { return $last; } } return $last; } 

Это должно дать вам то, что вам нужно.

попробуйте это: (он не был протестирован)

 function searchArray($needle, $haystack){ $return = $haystack[0]; $prevReturn = $return; foreach($haystack as $key=>$val){ if($needle > $val) { $prevReturn = $return; $return = $val; } if($val >= $needle) { $prevReturn = $return; $return = $val; break; } } if((($return+$needle)/2) > (($prevReturn+$needle)/2)){ //means that the needle is closer to $prevReturn return $prevReturn; } else return $return; }