Генерация неповторяющегося случайного числа в JavaScript - PullRequest
1 голос
/ 04 мая 2019

Как мне убедиться, что я не получаю повторение случайного числа? Сейчас это не работает. Я использую локальный массив для хранения предыдущих результатов.

getUniqueRandomNumber(x){
     var index;
     var viewedIndices = [];
     index = Math.floor(Math.random() * (x));
     if(viewedIndices.includes(index)) 
     {
       viewedIndices.push(index);
       this.getUniqueRandomNumber(x);
     }
     else { 
       console.log(index);
       return index;
    }
 }

Ответы [ 4 ]

3 голосов
/ 04 мая 2019

Вам необходимо сделать viewedIndicies постоянным , чтобы при дальнейших вызовах getUniqueRandomNumber можно было видеть ранее добавленные элементы.Вместо того, чтобы отслеживать индикаторы, вероятно, будет проще отслеживать только выбранные простые числа .Вы можете использовать Set вместо массива для меньшей вычислительной сложности (.has равно O(1), .includes равно O(N)).

const makeGetUniqueRandomNumber = (x) => {
  const chosenNumbers = new Set();
  return () => {
    if (chosenNumbers.size === x) {
      throw new Error('No more uniques!');
    }
    let num;
    do {
      num = Math.floor(Math.random() * x);
    } while (chosenNumbers.has(num));
    chosenNumbers.add(num);
    return num;
  };
};

const getRand5 = makeGetUniqueRandomNumber(5);
console.log(
  getRand5(),
  getRand5(),
  getRand5(),
  getRand5(),
  getRand5()
);
try {
  getRand5();
} catch(e) {
  console.log(e.message);
}

const anotherGetRand5 = makeGetUniqueRandomNumber(5);
console.log(
  anotherGetRand5(),
  anotherGetRand5(),
  anotherGetRand5(),
  anotherGetRand5(),
  anotherGetRand5()
);

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

Если вы разрабатываете в древней среде, которая не понимает синтаксис ES6 (ES2015), то вы можете использоватьмассив вместо набора и передать код через Babel:

"use strict";

var makeGetUniqueRandomNumber = function makeGetUniqueRandomNumber(x) {
  var chosenNumbers = [];
  return function () {
    if (chosenNumbers.length === x) {
      throw new Error('No more uniques!');
    }

    var num;

    do {
      num = Math.floor(Math.random() * x);
    } while (chosenNumbers.includes(num));

    chosenNumbers.push(num);
    return num;
  };
};

var getRand5 = makeGetUniqueRandomNumber(5);
console.log(getRand5(), getRand5(), getRand5(), getRand5(), getRand5());

try {
  getRand5();
} catch (e) {
  console.log(e.message);
}

var anotherGetRand5 = makeGetUniqueRandomNumber(5);
console.log(anotherGetRand5(), anotherGetRand5(), anotherGetRand5(), anotherGetRand5(), anotherGetRand5());
2 голосов
/ 05 мая 2019

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

const usedIndexes = [];    
function getUniqueRandomNumber(x) {
  const index = Math.floor(Math.random() * (x));
  if (usedIndexes.includes(index)) {
    return this.getUniqueRandomNumber(x);
  } else { 
    console.log(index);
    usedIndexes.push(index);
    return index;
  }
}

Кроме того, я бы подумал об использовании Set в этой ситуации вместо массива.

const usedIndexes = new Set();    
function getUniqueRandomNumber(max, min = 0) {
  const newNumber = Math.floor(Math.random() * (max - min) + min);
  if (usedIndexes.has(newNumber)) {
    return this.getUniqueRandomNumber(max, min);
  } else { 
    usedIndexes.add(newNumber);
    return newNumber;
  }
}

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

0 голосов
/ 05 мая 2019

Вы просто хотите, чтобы код, который вы написали, работал или вы хотите лучшее решение?Выбор случайных чисел до тех пор, пока вы не получите повторение, - это рецепт катастрофы, так как ваша программа останавливается на несколько секунд, пытаясь найти число, которое не было использовано.Конечно, если вы запрашиваете только несколько цифр, возможно, это не будет длиться вечно, но тогда код находится в вашей кодовой базе, и через 5 лет его использует кто-то другой, не зная, что в коде есть бомба замедленного действия.Представьте, что в массиве 10000 элементов, а 9999 выбрано.Может потребоваться 1 миллион повторных попыток, прежде чем он завершит выбор одного неиспользованного индекса.

Код, похоже, выбирает индексы с именами переменных, такими как index и viewedIndices

Oneспособ выбрать случайные элементы просто удалить затем из массива наугад.Если вам нужно сделать копию массива

const array = ["a", "b", "c", "d", "e", "f", "g"];

while (array.length) {
  const ndx = Math.random() * array.length | 0;
  const elem = array.splice(ndx, 1)[0];
  console.log(elem);
}

Примечание: использование Math.random() * value | 0 для получения случайного 0 -> положительного целого числа быстрее, чем Math.floor(Math.random() * value), поскольку | является оператором, а не функцией, связанной сMath объект, который необходимо проверять при каждом вызове, чтобы увидеть, был ли он заменен.

0 голосов
/ 05 мая 2019

Это не работает, потому что каждый раз, когда вы вызываете getUniqueRandomNumber , он повторно инициализирует ваш массив visibleIndices в пустой массив.Поэтому, чтобы ваш код работал, объявите этот массив над вызовом функции.

...