一尘不染

在JS中生成非重复随机数

javascript

我有以下功能

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

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

有人可以在逻辑上帮助我吗?确保我的数字不重复的最佳方法是什么?


阅读 456

收藏
2020-05-01

共1个答案

一尘不染

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

正如您在方法中发现的那样,这样做不会冒花费更长的时间查找未使用的数字的风险。

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-YatesShuffle那样高效,因为您仍在添加splice数组。但是不同之处在于,您现在仅在需要时才进行该工作,而不是全部先进行,因此根据您的用例,这可能会更好。

2020-05-01