Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a random value from 1~N but excluding several specific values in PHP?

rand(1,N) but excluding array(a,b,c,..),

is there already a built-in function that I don't know or do I have to implement it myself(how?) ?

UPDATE

The qualified solution should have gold performance whether the size of the excluded array is big or not.

like image 689
Gtker Avatar asked Apr 23 '10 12:04

Gtker


2 Answers

No built-in function, but you could do this:

function randWithout($from, $to, array $exceptions) {
    sort($exceptions); // lets us use break; in the foreach reliably
    $number = rand($from, $to - count($exceptions)); // or mt_rand()
    foreach ($exceptions as $exception) {
        if ($number >= $exception) {
            $number++; // make up for the gap
        } else /*if ($number < $exception)*/ {
            break;
        }
    }
    return $number;
}

That's off the top of my head, so it could use polishing - but at least you can't end up in an infinite-loop scenario, even hypothetically.

Note: The function breaks if $exceptions exhausts your range - e.g. calling randWithout(1, 2, array(1,2)) or randWithout(1, 2, array(0,1,2,3)) will not yield anything sensible (obviously), but in that case, the returned number will be outside the $from-$to range, so it's easy to catch.

If $exceptions is guaranteed to be sorted already, sort($exceptions); can be removed.

Eye-candy: Somewhat minimalistic visualisation of the algorithm.

like image 72
pinkgothic Avatar answered Sep 22 '22 08:09

pinkgothic


I don't think there's such a function built-in ; you'll probably have to code it yourself.

To code this, you have two solutions :

  • Use a loop, to call rand() or mt_rand() until it returns a correct value
    • which means calling rand() several times, in the worst case
    • but this should work OK if N is big, and you don't have many forbidden values.
  • Build an array that contains only legal values
    • And use array_rand to pick one value from it
    • which will work fine if N is small
like image 29
Pascal MARTIN Avatar answered Sep 23 '22 08:09

Pascal MARTIN