JS中生成不重复的随机数

新手上路,请多包涵

我有以下功能

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

我猜这是因为我在内部调用函数太多次了。这意味着我的代码不好。

有人可以帮我解决逻辑吗?确保我的号码不重复的最佳方法是什么?

原文由 user1214678 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 748
2 个回答

如果我理解正确,那么您只是在寻找数字 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 以回忆随机数。

正如您在方法中发现的那样,这不会导致查找未使用的号码的时间越来越长。

编辑:阅读 本文 并在 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]);

基本上,它通过避免使用“昂贵”的数组操作来提高效率。

奖金编辑:另一种可能性是使用 发电机(假设你有 支持):

 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 那样高效,因为您仍然是 splice 数组。但不同之处在于,您现在只在需要时才做这项工作,而不是提前完成所有工作,因此根据您的用例,这可能会更好。

原文由 Ben Jackson 发布,翻译遵循 CC BY-SA 3.0 许可协议

//random number without repetition in JavaScript, Just in one line;
//it can be used as _id;
//it not need to store or check;

 const myRnId = () => parseInt(Date.now() * Math.random());

console.log(myRnId()); // any random number included timeStamp;

原文由 Shahzad Harim 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题