简体   繁体   中英

Find number which is greater than or equal to N in an array

If I have a PHP array:

$array

With values:

45,41,40,39,37,31

And I have a variable:

$number = 38;

How can I return the value?:

39

Because that is the closest value to 38 (counting up) in the array?

Regards,

taylor

<?php
function closest($array, $number) {

    sort($array);
    foreach ($array as $a) {
        if ($a >= $number) return $a;
    }
    return end($array); // or return NULL;
}
?>

Here is a high-level process to get the desired results and work for any array data:

  • Filter the array keeping on values greater than or equal to the target and then select the lowest remaining value. This is the "best" value (which may be "nothing" if all the values were less) -- this is O(n)
  • Alternatively, sort the data first and see below -- this is O(n lg n) (hopefully)

Now, assuming that the array is sorted ASCENDING, this approach would work:

  • Loop through the array and find the first element which is larger than or equal to the target -- this is O(n)

And if the array is DESCENDING (as in the post), do as above, but either:

  • Iterate backwards -- this is O(n)
  • Sort it ASCENDING first (see fardjad's answer) -- this is O(n lg n) (hopefully)
  • Iterate forwards but keep a look-behind value (to remember "next highest" if the exact was skipped) -- this is O(n)

Happy coding.

EDIT typo on array_search

Yo... Seems easy enough. Here's a function

<?php 
$array = array(45,41,40,39,37,31);

   function closest($array, $number){
    #does the array already contain the number?
    if($i = array_search( $number, $array)) return $i;

    #add the number to the array
    $array[] = $number;

    #sort and refind the number
    sort($array);
    $i = array_search($number, $array);

    #check if there is a number above it
    if($i && isset($array[$i+1])) return $array[$i+1];

    //alternatively you could return the number itself here, or below it depending on your requirements
    return null;
}

to Run echo closest($array, 38);

Here's a smaller function that will also return the closest value. Helpful if you don't want to sort the array (to preserve keys).

function closest($array, $number) {
    //does an exact match exist?
    if ($i=array_search($number, $array)) return $i;

    //find closest
    foreach ($array as $match) {
        $diff = abs($number-$match); //get absolute value of difference
        if (!isset($closeness) || (isset($closeness) && $closeness>$diff)) {
            $closeness = $diff;
            $closest = $match;
        }
    }
    return $closest;
}

Do a linear scan of each number and update two variables and you'll be done.

Python code (performance is O(N), I don't think it's possible to beat O(N)):

def closestNum(numArray, findNum):
    diff = infinity       # replace with actual infinity value
    closestNum = infinity # can be set to any value
    for num in numArray:
        if((num - findNum) > 0 and (num - findNum) < diff):
            diff = num - findNum
            closestNum = num
    return closestNum

Please add null checks as appropriate.

If you really want the value that's "closest" in distance, even if it's a lesser value, try this, which @Jason gets most of the credit for.

Imagine a scenario when you want the closest number to 38.9 in the following:

$array = array(37.5, 38.5, 39.5);

Most of the solutions here would give you 39.5, when 38.5 is much closer. This solution would only take the next highest value if what you're looking is in the exact middle between two numbers in the array:

function nearest_value($value, $array) {
if (array_search($value, $array)) {
    return $value;
} else {
    $array[] = $value;
    sort($array);
    $key = array_search($value, $array);
    if ($key == 0) { return $array[$key+1]; }
    if ($key == sizeof($array)-1) { return $array[$key-1]; }
    $dist_to_ceil = $array[$key+1]-$value;
    $dist_to_floor = $value-$array[$key-1];
    if ($dist_to_ceil <= $dist_to_floor) {
        return $array[$key+1];
    } else {
        return $array[$key-1];
    }
}
}

What it lacks in elegance, it makes up for in accuracy. Again, much thanks to @Jason.

Try this simple PHP function:

<?php
function nearest($number, $numbers) {
    $output = FALSE;
    $number = intval($number);
    if (is_array($numbers) && count($numbers) >= 1) {
        $NDat = array();
        foreach ($numbers as $n)
            $NDat[abs($number - $n)] = $n;
        ksort($NDat);
        $NDat   = array_values($NDat);
        $output = $NDat[0];
    }
    return $output;
}

echo nearest(90, array(0, 50, 89, 150, 200, 250));
?>

I made a shorter function for that:

function nearestNumber($num, $array) {
    if(!in_array($num, $array)) $array[] = $num;
    sort($array);
    $idx = array_search($num, $array);
    if(($array[$idx] -$array[$idx-1]) >= ($array[$idx+1] -$array[$idx])) return $array[$idx+1];
    else return $array[$idx-1];
}

Works great in my case: $array = array(128,160,192,224,256,320); $num = 203 $array = array(128,160,192,224,256,320); $num = 203 :)

It's taking the nearest number and if there's the same distance between two numbers (like 208 for my example), the next highest number is used.

+1 to Jason.

My implementation below, but not as brisk

$array = array(1,2,4,5,7,8,9);

function closest($array, $number) {
    $array = array_flip($array);

    if(array_key_exists($number, $array)) return $number;

    $array[$number] = true;

    sort($array);

    $rendered = array_slice($array, $number, 2, true); 

    $rendered = array_keys($rendered);

    if(array_key_exists(1, $rendered)) return $rendered[1]; 

    return false;
}

print_r(closest($array, 3));

You could use array_reduce for this, which makes it more functional programming style:

function closest($needle, $haystack) {
    return array_reduce($haystack, function($a, $b) use ($needle) {
        return abs($needle-$a) < abs($needle-$b) ? $a : $b;
    });
}

For the rest, this follows the same principle as the other O(n) solutions.

Here is my solution.

$array=array(10,56,78,17,30);
$num=65;
$diff=$num;
$min=$num;

foreach($array as $a){
          if( abs($a-$num)< $diff ){
              $diff=abs($a-$num);
              $min=$a;
          }
}

echo $min;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM