0

Генерация УНИКАЛЬНЫХ случайных чисел в заданном диапазоне

23

Заголовок: Как сгенерировать уникальные случайные числа в заданном диапазоне?

Тело вопроса: Мне нужно сгенерировать уникальные случайные числа в заданном диапазоне, как я могу это сделать? Я уже могу генерировать случайные числа с помощью следующего кода:

generator:
$arr = [];
$x = rand($min, $max);
$len = count($arr);
$flag = 0;
for($i = 0; $i < $len; $i++) {
    if ($flag === 1)
        goto generator;
    if ($x === $arr[$i])
        $flag = 1;
}
$arr[$index] = $x;
$index++; 
goto generator;

Я понимаю, что этот код неэффективен, поэтому мне нужен более оптимизированный вариант! Пожалуйста, помогите!

Пример: Если мне нужно сгенерировать 3 уникальных числа в диапазоне от 1 до 15, они должны быть такими, как 5, 9, 1, но не 3, 1, 2 (где 3 — количество чисел, которые я хочу сгенерировать).

5 ответ(ов)

1

Для генерации массива уникальных случайных чисел в заданном диапазоне можно воспользоваться функцией range() для создания массива чисел, а затем перемешать его с помощью функции shuffle(). Ниже представлен пример функции, которая принимает минимальное и максимальное значения, а также количество требуемых случайных чисел.

Пример функции

function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
    $numbers = range($min, $max); // Создаём массив чисел от $min до $max
    shuffle($numbers);             // Перемешиваем массив случайным образом
    return array_slice($numbers, 0, $quantity); // Возвращаем заданное количество уникальных чисел
}

Использование функции

<?php
print_r(UniqueRandomNumbersWithinRange(0, 25, 5));
?>

Возможный результат

В результате выполнения приведенного кода вы можете получить массив с 5 уникальными случайными числами в диапазоне от 0 до 25, например:

Array
(
    [0] => 14
    [1] => 16
    [2] => 17
    [3] => 20
    [4] => 1
)

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

0

Можно перевести данный ответ на русский язык в стиле StackOverflow следующим образом:


Я был заинтересован в том, как принятый ответ сравнивается с моим. Полезно отметить, что гибридный подход, объединяющий оба решения, может быть выгодным; по сути, функция, которая условно использует одно или другое в зависимости от определённых значений, может быть лучшим выбором:

# Принятый ответ
function randRange1($min, $max, $count)
{
    $numbers = range($min, $max);
    shuffle($numbers);
    return array_slice($numbers, 0, $count);
}

# Мой ответ
function randRange2($min, $max, $count)
{
    $i = 0;
    $range = array();
    while ($i++ < $count) {
        while(in_array($num = mt_rand($min, $max), $range));
        $range[] = $num;
    }
    return $range;
}

echo 'randRange1: малый диапазон, высокое количество' . PHP_EOL;
$time = microtime(true);
randRange1(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;

echo 'randRange2: малый диапазон, высокое количество' . PHP_EOL;
$time = microtime(true);
randRange2(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;

echo 'randRange1: широкий диапазон, малое количество' . PHP_EOL;
$time = microtime(true);
randRange1(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;

echo 'randRange2: широкий диапазон, малое количество' . PHP_EOL;
$time = microtime(true);
randRange2(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;

Результаты:

randRange1: малый диапазон, высокое количество
0.019910097122192

randRange2: малый диапазон, высокое количество
1.5043621063232

randRange1: широкий диапазон, малое количество
2.4722430706024

randRange2: широкий диапазон, малое количество
0.0001051425933837

Как видно, если вы используете меньший диапазон и большее количество возвращаемых значений, принятый ответ определенно является оптимальным. Однако, как я и ожидал, для более широких диапазонов и меньших количеств значений принятому ответу потребуется намного больше времени, так как он должен хранить каждое возможное значение в диапазоне. Вы даже рискуете превысить лимит памяти PHP. Гибридный подход, который оценивает отношение между диапазоном и количеством, и условно выбирает генератор, мог бы стать наилучшим вариантом.

0

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

function getDistinctRandomNumbers($nb, $min, $max) {
    if ($max - $min + 1 < $nb)
        return false; // или выбросить исключение

    $res = array();
    do {
        $res[mt_rand($min, $max)] = 1;
    } while (count($res) !== $nb);
    return array_keys($res); 
}

Плюсы: таким образом можно избежать использования in_array и не создавать огромный массив. Это делает функцию быстрой и экономит много памяти.

Минусы: по мере уменьшения соотношения (объем/количество) скорость снижается (но остается приемлемой). При одинаковом соотношении относительная скорость увеличивается с увеличением диапазона. ()*

() Я понимаю этот факт, так как при первом выборе свободных целых чисел больше (особенно на начальных этапах), но если у кого-то есть математическая формула, описывающая это поведение, буду рад её увидеть, не стесняйтесь делиться.*

Заключение: лучшая "универсальная" функция, похоже, является смесью между этой функцией и функцией @Anne, которая более эффективна при небольшом соотношении. Эта функция должна переключаться между двумя подходами, когда требуется определенное количество и достигается заданное соотношение (объем/количество). Поэтому нужно учесть сложность/время теста для определения этого момента.

0

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

Пример на PHP:

$arr = array();

for ($i=1; $i<=101; $i++) {
    $arr[] = $i;
}

shuffle($arr);

print_r($arr);

На выходе вы получите нечто подобное:

Array
(
    [0] => 16
    [1] => 93
    [2] => 46
    [3] => 55
    [4] => 18
    [5] => 63
    [6] => 19
    [7] => 91
    [8] => 99
    [9] => 14
    [10] => 45
    [11] => 68
    [12] => 61
    [13] => 86
    [14] => 64
    [15] => 17
    [16] => 27
    [17] => 35
    [18] => 87
    [19] => 10
    [20] => 95
    [21] => 43
    [22] => 51
    [23] => 92
    [24] => 22
    [25] => 58
    [26] => 71
    [27] => 13
    [28] => 66
    [29] => 53
    [30] => 49
    [31] => 78
    [32] => 69
    [33] => 1
    [34] => 42
    [35] => 47
    [36] => 26
    [37] => 76
    [38] => 70
    [39] => 100
    [40] => 57
    [41] => 2
    [42] => 23
    [43] => 15
    [44] => 96
    [45] => 48
    [46] => 29
    [47] => 81
    [48] => 4
    [49] => 33
    [50] => 79
    [51] => 84
    [52] => 80
    [53] => 101
    [54] => 88
    [55] => 90
    [56] => 56
    [57] => 62
    [58] => 65
    [59] => 38
    [60] => 67
    [61] => 74
    [62] => 37
    [63] => 60
    [64] => 21
    [65] => 89
    [66] => 3
    [67] => 32
    [68] => 25
    [69] => 52
    [70] => 50
    [71] => 20
    [72] => 12
    [73] => 7
    [74] => 54
    [75] => 36
    [76] => 28
    [77] => 97
    [78] => 94
    [79] => 41
    [80] => 72
    [81] => 40
    [82] => 83
    [83] => 30
    [84] => 34
    [85] => 39
    [86] => 6
    [87] => 98
    [88] => 8
    [89] => 24
    [90] => 5
    [91] => 11
    [92] => 73
    [93] => 44
    [94] => 85
    [95] => 82
    [96] => 75
    [97] => 31
    [98] => 77
    [99] => 9
    [100] => 59
)

Таким образом, вы получите массив с 100 уникальными случайными числами.

0

Если вам нужно получить 5 случайных чисел в диапазоне от 1 до 15, вы можете использовать следующий код:

var_dump(getRandomNumbers(1, 15, 5));

function getRandomNumbers($min, $max, $count)
{
    if ($count > (($max - $min) + 1)) {
        return false;
    }
    $values = range($min, $max);
    shuffle($values);
    return array_slice($values, 0, $count);
}

Этот код сначала проверяет, не превышает ли запрашиваемое количество случайных чисел доступный диапазон. Если count больше, чем количество чисел в диапазоне, функция вернет false. В противном случае она создаст массив чисел в указанном диапазоне, перемешает их с помощью shuffle() и вернет первые count значений.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь