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

前端 未结 7 2012
不知归路
不知归路 2020-12-10 06:56

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?)

相关标签:
7条回答
  • 2020-12-10 07:08

    What you need to do is calculate an array of skipped locations so you can pick a random position in a continuous array of length M = N - #of exceptions and easily map it back to the original array with holes. This will require time and space equal to the skipped array. I don't know php from a hole in the ground so forgive the textual semi-psudo code example.

    1. Make a new array Offset[] the same length as the Exceptions array.
    2. in Offset[i] store the first index in the imagined non-holey array that would have skipped i elements in the original array.
    3. Now to pick a random element. Select a random number, r, in 0..M the number of remaining elements.
    4. Find i such that Offset[i] <= r < Offest[i+i] this is easy with a binary search
    5. Return r + i

    Now, that is just a sketch you will need to deal with the ends of the arrays and if things are indexed form 0 or 1 and all that jazz. If you are clever you can actually compute the Offset array on the fly from the original, it is a bit less clear that way though.

    0 讨论(0)
  • 2020-12-10 07:10

    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
    0 讨论(0)
  • 2020-12-10 07:11

    The simplest way...

    <?php
    
    function rand_except($min, $max, $excepting = array()) {
    
        $num = mt_rand($min, $max);
    
        return in_array($num, $excepting) ? rand_except($min, $max, $excepting) : $num;
    }
    ?>
    
    0 讨论(0)
  • 2020-12-10 07:21

    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.

    0 讨论(0)
  • 2020-12-10 07:21

    This is the fastest & best performance way to do it :

    $all =  range($Min,$Max);
    $diff = array_diff($all,$Exclude);
    shuffle($diff );
    $data = array_slice($diff,0,$quantity);
    
    0 讨论(0)
  • 2020-12-10 07:26

    Maybe its too late for answer, but I found this piece of code somewhere in my mind when trying to get random data from Database based on random ID excluding some number.

    $excludedData = array(); // This is your excluded number
    $maxVal = $this->db->count_all_results("game_pertanyaan"); // Get the maximum number based on my database
    
    $randomNum = rand(1, $maxVal); // Make first initiation, I think you can put this directly in the while > in_array paramater, seems working as well, it's up to you
    while (in_array($randomNum, $excludedData)) {
      $randomNum = rand(1, $maxVal);
    }
    
    $randomNum; //Your random number excluding some number you choose

    0 讨论(0)
提交回复
热议问题