3

I have an array, for example (it can be anything, but it's already ordered):

array(1,7, 12, 18, 25);

I need to find what number is the closest to that array.

Taking the above array:

$needle = 11;

The number in array i want to retrieve is 7. The closest number to 11 should be 12, but i dont want the closest number, i want the minor closest number, if that makes any sense.

Another examples:

  • Entering 26 the retrieved number should be 25
  • Entering 1 the retrieved number should be 1
  • Entering 6 the retrieved number should be 1
  • Entering 7 the retrieved number should be 7
  • Entering 16 the retrieved number should be 12

I found a nice function, but it does only retrieve the closest number, and not the minor closest number:

function closestnumber($number, $candidates) {
 for($i = 0; $i != sizeof($candidates); $i++) {
  $results[$i][0] = abs($candidates[$i] - $number);
  $results[$i][1] = $i;
 }
 sort($results);
 $end_result['closest'] = $candidates[$results[0][1]];
 $end_result['difference'] = $results[0][0];
 return $end_result;
}

$closest = closestnumber(8,array(1,7, 12, 18, 25));
echo "Closest: ".$closest['closest']."<br>";
echo "Difference: ".$closest['difference'];

Thanks in advance.

user538927
  • 33
  • 3

3 Answers3

5
$myArray = array(1,7, 12, 18, 25); 
$needle = 11; 

$resultKey = array_search(max(array_intersect(array_values($myArray),range(0,$needle))),$myArray); 
$result = $myArray[$resultKey];

EDIT

Assumes array values will always be positive integers

Simplified version

$myArray = array(1,7, 12, 18, 25); 
$needle = 11; 

$result = max(array_intersect(array_values($myArray),range(0,$needle))); 
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
2

This looks like homework but I'll humour you:

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;
}
Andre
  • 3,150
  • 23
  • 23
  • Good general solution. `$last = null` may be a more appropriate initializer. `$key` isn't used or needed. A binary search might be more appropriate if the array is large. – Matthew Dec 12 '10 at 18:42
  • Note that this requires the values to be sorted in ascending order. – Gumbo Dec 12 '10 at 18:44
  • Good points, edited. @Gumbo: He does state that the array is already ordered. – Andre Dec 12 '10 at 18:45
1

Only test candidates that are less than or equal to your number. And if you always remember only the best solution you don’t need to sort the solutions to find the best.

So try this:

function closestnumber($number, $candidates) {
    $best = null;
    foreach ($candidates as $candidate) {
        if ($candidate <= $number) {
            if (is_null($best) || $diff > $number - $candidate) {
                $diff = $number - $candidate;
                $best = $candidate;
            }
        }
    }
    if (is_null($best)) {
        return false;
    }
    return array('closest' => $best, 'difference' => $diff);
}
Gumbo
  • 643,351
  • 109
  • 780
  • 844