Ниже приведен очень простой пример генерации случайного целого числа в JS, где я никоим образом не "расширяю границы".
Я генерирую только 500 уникальных случайных чисел из очень большого пространства, 10 ^ 6.
И все же, если вы продолжите нажимать кнопку, вы будете иногда видеть 499 или 498 уникальных из 500. Это случается не очень часто, но это происходит, возможно, при каждом 10-м или 15-м щелчке. Это почему? Мое пространство составляет 1 миллион. Я не ожидаю столкновения в выборке 500 с частотой каждого 10-го или 20-го клика.
Чтобы проверить, продолжайте нажимать кнопку и смотреть консоль.
function run() {
var nums = new Set();
for (var i = 0; i < 500; i++) {
nums.add(randomInteger10to6th());
}
console.clear();
console.log('Random 10^6 Unique Integer set: ' + nums.size);
}
function randomInteger10to6th() {
return Math.round(Math.random() * Math.pow(10,6))
}
<button id="run" onclick="run();">Run 500 Random Integers, Space: 10^6</button>
Вероятность того, что вы увидите все уникальные числа, когда выберете 500 случайных чисел из 1-1e6, может быть рассчитана следующим образом: 1e6/1e6 * 999,999/1e6 * 999,998/1e6 *... * 999,501/1e6
Это выходит около 0,88
Это означает, что более чем в 10% случаев в вашем списке из 500 случайностей будет хотя бы один дубликат.
Вы можете проверить это поведение в приведенном ниже фрагменте для 100 экспериментов:
function run() {
var nums = new Set();
for (var i = 0; i < 500; i++) {
nums.add(randomInteger10to6th());
}
return nums;
}
function randomInteger10to6th() {
return Math.round(Math.random() * Math.pow(10, 6))
}
// perform 100 experiments and see how many have duplicates
var uniques = 0, collisions = 0;
for (var i = 0; i < 100; i++) {
var nums = run();
if (nums.size === 500) uniques++;
else collisions++;
}
console.log('Runs that generated unique numbers', uniques);
console.log('Runs that resulted in collisions', collisions);
Поскольку вы генерируете сравнительно небольшое количество случайных чисел из большой выборки, вы сможете восстановить новое число при столкновении. Добавление случайных чисел до 500 приведет к нескольким дополнительным вызовам в генератор случайных чисел, но это гарантирует 500 уникальных номеров:
function run() {
var nums = new Set();
while (nums.size < 500){
nums.add(randomInteger10to6th());
}
console.clear();
console.log('Random 10^6 Unique Integer set: ' + nums.size);
}
function randomInteger10to6th() {
return Math.round(Math.random() * Math.pow(10,6))
}
<button id="run" onclick="run();">Run 500 Random Integers, Space: 10^6</button>
"Случайный" означает только это: он случайный. Каждое значение в диапазоне имеет одинаковую вероятность быть выбранным, независимо от того, что было выбрано ранее. Таким образом, даже если он выбрал число 5, например, у него все еще остается тот же шанс выбрать 5 раз, как и при выборе любого другого числа. Вы не должны ожидать случайных чисел, чтобы избежать дубликатов - если бы они сделали, они не были бы случайными :)
Вы также можете использовать простые массивы вместо Set()
. Сначала создайте массив из 500 индексов, затем заполните его.
function run() {
/* first create an array with 500 slots, then fill it with
undefined ( fill() without args is undefined ). For the
last step map through 500 slots of undefined and overwrite
it with a random number */
return new Array(500).fill().map(x => Math.round(Math.random() * Math.pow(10,6)))
}
console.log(run().length)
<button id="run" onclick="run();">Run 500 Random Integers, Space: 10^6</button>
И если вы хотите удалить дубликаты, вы можете просто отфильтровать их пересчитать.
function run() {
// same like the upper function but with a duplicates filter
let arrayWithNumbers = new Array(500).fill().map(x => Math.round(Math.random() * Math.pow(10,6))).filter((item, idx, self) => self.indexOf(item) == idx)
// run again if array less than 500
if(arrayWithNumbers.length !== 500) {
run()
}
return arrayWithNumbers
}
console.log(run().length)
<button id="run" onclick="run();">Run 500 Random Integers, Space: 10^6</button>