PHP rand() исключает определенные числа

У меня есть это:

<?php  $n = rand(1,1600); echo $n ?>

Я хочу исключить из случайных чисел, скажем, 234, 1578, 763, 1274 и другие числа. Как мне это сделать?

Ответ 1

<?php

while( in_array( ($n = rand(1,1600)), array(234, 1578 ,763 , 1274) ) );

Ответ 2

Попробуйте это

do {   
    $n = rand(1,1600);

} while(in_array($n, array(234, 1578 ,763 , 1274 ));
echo $n;

Ответ 3

Проверьте, не номер, который вам не нужен, если он получает новое случайное число.

function getRandomNumber() {
    do {
        $n = mt_rand(1,1600);
    } while(in_array($n, array(234,1578, 763, 1274)));

    return $n;
}

Ответ 4

Или избегайте создания циклов со случайным (возможно, бесконечным) временем выполнения:

/**
 * Returns a random integer between $min and $max (inclusive) and
 * excludes integers in $exarr, returns false if no such number
 * exists.
 * 
 * $exarr is assumed to be sorted in increasing order and each
 * element should be unique.
 */
function random_exclude($min, $max, $exarr = array()) {

    if ($max - count($exarr) < $min) {
        return false;
    }

    // $pos is the position that the random number will take
    // of all allowed positions
    $pos = rand(0, $max - $min - count($exarr));

    // $num being the random number
    $num = $min;

    // while $pos > 0, step to the next position
    // and decrease if the next position is available
    for ($i = 0; $i < count($exarr); $i += 1) {

        // if $num is on an excluded position, skip it
        if ($num == $exarr[$i]) {
            $num += 1;
            continue;
        }

        $dif = $exarr[$i] - $num;

        // if the position is after the next excluded number,
        // go to the next excluded number
        if ($pos >= $dif) {
            $num += $dif;

            // -1 because we're now at an excluded position
            $pos -= $dif - 1;
        } else {
            // otherwise, return the free position
            return $num + $pos;
        }
    }

    // return the number plus the open positions we still had to go
    return $num + $pos;
}

Эта функция выбирает случайную позицию и проходит массив исключений, чтобы найти свободную позицию. Время работы зависит от количества номеров, которые нужно исключить. Если вы хотите исключить определенные диапазоны, вы можете адаптировать алгоритм, чтобы принять это во внимание.

Ответ 5

Всегда используйте криптографически стойкие алгоритмы для генерации случайных чисел:

/**
 * @param int   $from     From number
 * @param int   $to       To number
 * @param array $excluded Additionally exclude numbers
 * @return int
 */
function randomNumber($from, $to, array $excluded = [])
{
    $func = function_exists('random_int') ? 'random_int' : 'mt_rand';

    do {
        $number = $func($from, $to);
    } while (in_array($number, $excluded, true));

    return $number;
}

var_dump(randomNumber(1, 100));
var_dump(randomNumber(1, 10, [5, 6, 7, 8]));
var_dump(randomNumber(1, 100, range(10, 90)));

Я бы также рекомендовал использовать библиотеку paragonie/random_compat для совместимости в случае использования нескольких версий PHP.

Ответ 6

Вы можете создать массив с действительными числами.

Затем ваше генерирование случайных чисел должно вернуть индекс в этот массив.

Ответ 7

Если у вас слишком много номеров для исключения, проще и быстрее просто повторить попытку, если вы найдете нежелательный номер:

$n = 0;
while (in_array($n, array(0, 234, 1578 ,763 , 1274))) {
  $n = rand(1,1600); 
}

echo $n;

Ответ 8

Другое решение для этого может быть следующим:

function random_number($min, $max, $exclude)
{
      $number = rand($min, $max);

  if(in_array($number, $exclude))
  {
      random_number($min, $max, $exclude);
  } else {
      return $number;
  }
}

$number = random_number(1,10, [2,5,6]);

Ответ 9

По мере того, как объем целых чисел, занесенных в "черный список", приближается к объему всего диапазона целых чисел, становится все более убедительным прислушиваться к совету @regenschein.

Не итеративный подход может выглядеть так:

$range = range(1, 1600);
$blacklist = [234, 1578, 763, 1274]; // 4 blacklisted versus 1600 full range is NOT compelling
$valids = array_diff($range, $blacklist);
echo array_values($valids)[rand(0, count($valids) - 1)];
// or
echo $valids[array_rand($valids)];
// the two approaches use different randomizers

Или, если вы будете так же счастливы, вы можете сделать:

$blacklist = [234, 1578, 763, 1274];
$range = range(1, 1600);
$valids = array_diff($range, $blacklist);
shuffle($valids);
echo $valids[0];

* Обратите внимание, что array_diff() особенно array_diff() если вы хотите передать несколько массивов черного списка - просто разделите их запятыми.

Например:

var_export($valids = array_diff(range(1, 100), range(5, 50), range(61, 99), [55]));

Выход:

array (
  0 => 1,
  1 => 2,
  2 => 3,
  3 => 4,
  50 => 51,
  51 => 52,
  52 => 53,
  53 => 54,
  55 => 56,
  56 => 57,
  57 => 58,
  58 => 59,
  59 => 60,
  99 => 100,
)

Ответ 10

Я знаю, что это немного устарело, но я думаю, что операция пытается перетасовать целые числа. Если так, то следующий метод лучше

$array = array(1,2,3,4,5,6,7);
shuffle($array);

Этот код рандомизирует порядок точных элементов массива без повторения и возвращает результат внутри самого массива.