我有以下功能
function randomNum(max, used){
newNum = Math.floor(Math.random() * max + 1);
if($.inArray(newNum, used) === -1){
console.log(newNum + " is not in array");
return newNum;
}else{
return randomNum(max,used);
}
}
基本上,我创建了一个介于 1 - 10 之间的随机数,并通过将其添加到数组并检查新创建的数字来检查该数字是否已经创建。我通过将它添加到变量来调用它..
UPDATED:
for(var i=0;i < 10;i++){
randNum = randomNum(10, usedNums);
usedNums.push(randNum);
//do something with ranNum
}
这有效,但在 Chrome 中我收到以下错误:
Uncaught RangeError: Maximum call stack size exceeded
我猜这是因为我在内部调用函数的次数太多了。这意味着我的代码不好。
谁能帮我解释一下逻辑?确保我的号码不重复的最佳方法是什么?
最佳答案
如果我没理解错,那么您只是在寻找数字 1-10 的排列(即没有重复的随机数字)? 也许尝试生成这些数字的随机列表,一次,在开始时,然后按照你的方式处理这些数字?
这将计算 nums
中数字的随机排列:
var nums = [1,2,3,4,5,6,7,8,9,10],
ranNums = [],
i = nums.length,
j = 0;
while (i--) {
j = Math.floor(Math.random() * (i+1));
ranNums.push(nums[j]);
nums.splice(j,1);
}
因此,例如,如果您正在寻找 1 到 20 之间的随机数,这些随机数也是偶数,那么您可以使用:
nums = [2,4,6,8,10,12,14,16,18,20];
然后只需通读 ranNums
以记忆随机数。
这不会像您在方法中发现的那样,会花费越来越长的时间来查找未使用的号码。
编辑:阅读后this并在 jsperf 上运行测试,似乎更好的方法是 Fisher–Yates Shuffle:
function shuffle(array) {
var i = array.length,
j = 0,
temp;
while (i--) {
j = Math.floor(Math.random() * (i+1));
// swap randomly chosen element with current element
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
var ranNums = shuffle([1,2,3,4,5,6,7,8,9,10]);
基本上,避免使用“昂贵”的数组操作会更高效。
BONUS EDIT:另一种可能性是使用 generators (假设你有 support ):
function* shuffle(array) {
var i = array.length;
while (i--) {
yield array.splice(Math.floor(Math.random() * (i+1)), 1)[0];
}
}
然后使用:
var ranNums = shuffle([1,2,3,4,5,6,7,8,9,10]);
ranNums.next().value; // first random number from array
ranNums.next().value; // second random number from array
ranNums.next().value; // etc.
其中 ranNums.next().value
最终将评估为 undefined
一旦您遍历了随机排列的数组中的所有元素。
总体而言,这不会像 Fisher–Yates Shuffle 那样高效,因为您仍在拼接
-ing 数组。但不同之处在于,您现在只在需要时才做这项工作,而不是提前完成所有工作,因此根据您的用例,这可能会更好。
关于javascript - JS中生成不重复的随机数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18806210/