2011-01-14 2 views
1

У меня есть вопрос, касающийся JavaScript Math.random():Javascript: Исключить элемент из случайного набора - (любознательность)

Я (для игры я строй) случайным образом генерировать каждое число из заданного набора (т.е. от 0 до 1000), и каждый раз, когда мне приходится генерировать число, я должен проверить, был ли этот номер уже «сгенерирован».

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

/* ... */ 
for(var i = 0; i<upperBound; i++){ 
    var randN = Math.floor(Math.random()*upperBound); 
    while(myRandomNumbers.contains(randN)){ 
     loops++; 
     randN = Math.floor(Math.random()*upperBound); 
    } 
    myRandomNumbers.push(randN); 
} 
/* ... */ 

running example here

Я хотел бы знать: это лучший способ для достижения этой цели? или есть ли какие-либо способы, а не цикл, пока он не породит «хороший» номер, чтобы исключить конкретный набор в случайном генерации?

Спасибо большое всем!

+0

Может быть, [этот ответ] (http://stackoverflow.com/questions/3796786/random-number-generator-without-dupes-in-javascript) поможет. Или [этот] (http://stackoverflow.com/questions/2380019/generate-8-unique-random-numbers-between-1- и -100). – user113716

+0

@patrick dw: это мое решение, рекурсивное;) – stecb

+0

Да, я читал слишком быстро. – user113716

ответ

3
  1. Сформировать набор чисел в порядке.
  2. Сортировка списка в случайном порядке.

Вот пример с использованием naive, biased sort:

for (var nums=[],i=0;i<1000;++i) nums[i]=i+1; 
nums.sort(function(){ return Math.random()-0.5 }); 

Тогда вы можете просто pop() номера прочь nums, чтобы получить следующий «случайный» номер, гарантированно никогда не использовались ранее.

+0

Как уже отмечалось в ответе, это не даст очень случайного распределения и будет иметь разное смещение в разных браузерах. Перемешивание Фишера-Йейта не намного больше кода и будет намного лучше. –

+0

См. Функцию 'shuffle()' в файле, с которым я связан, для реализации Fisher-Yates. – Phrogz

1

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

Вот быстрый хак вашего примера реализации, чтобы показать этот метод в действии: http://www.jsfiddle.net/ZTLt9/8/

0

насчет массива булевых 1001 больших.

Если вы хотите, чтобы проверить числа было сформировано, все, что вам нужно сделать, это проверить номер на этой позиции в массиве:

if (!arr[randomnumber]){ 
    arr[randomnumber] = true; 
} 

В конце, вы можете сканировать массив, чтобы найти номера, которые вам нужны.

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

Нечто похожее на это было предметом одного из моих постов в блоге: http://www.jameswiseman.com/blog/2010/05/27/generate-and-sort-lottery-numbers/

1

Я бы создать массив и случайным образом перетасовать его:

function shuffle(arr) { 
    var shuffled = arr.slice(0), i = arr.length, temp, index; 
    while (i--) { 
     index = Math.floor(i * Math.random()); 
     temp = shuffled[index]; 
     shuffled[index] = shuffled[i]; 
     shuffled[i] = temp; 
    } 
    return shuffled; 
} 

// Create the array 
var i = 1000, arr = []; 
while (i--) arr[i] = i; 

// Shuffle it 
arr = shuffle(arr); 
0

Лучший способ, вероятно, будет генерировать массив чисел, затем перетасовать его с помощью Fisher-Yates shuffle.

Вот пример JavaScript приведен в статье Википедии: (. Это предполагает, у вас есть массив «а», который содержит элементы, которые вы хотите, чтобы перетасовать)

var n = a.length; 
for(var i = n - 1; i > 0; i--) { 
    var j = Math.floor(Math.random() * (i + 1)); 
    var tmp = a[i]; 
    a[i] = a[j]; 
    a[j] = tmp; 
} 

Смежные вопросы