在JS中生成非重复随机数

14 javascript jquery

我有以下功能

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

基本上我创建一个1到10之间的随机数,并通过将其添加到数组并检查新创建的数字来检查是否已创建该数字.我通过将其添加到变量来调用它.

UPDATED:
for(var i=0;i < 10;i++){

   randNum = randomNum(10, usedNums);
   usedNums.push(randNum);

   //do something with ranNum
}
Run Code Online (Sandbox Code Playgroud)

这有效,但在Chrome中我收到以下错误:

Uncaught RangeError: Maximum call stack size exceeded
Run Code Online (Sandbox Code Playgroud)

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

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

Ben*_*son 28

如果我理解的话,你只是在寻找数字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);
}
Run Code Online (Sandbox Code Playgroud)

因此,例如,如果您要查找1到20之间的随机数也是偶数,那么您可以使用:

nums = [2,4,6,8,10,12,14,16,18,20];
Run Code Online (Sandbox Code Playgroud)

然后只需通读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]);
Run Code Online (Sandbox Code Playgroud)

基本上,通过避免使用"昂贵的"阵列操作来提高效率.

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

function* shuffle(array) {

    var i = array.length;

    while (i--) {
        yield array.splice(Math.floor(Math.random() * (i+1)), 1)[0];
    }

}
Run Code Online (Sandbox Code Playgroud)

然后使用:

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.
Run Code Online (Sandbox Code Playgroud)

一旦你运行了混洗数组中的所有元素,ranNums.next().value最终将评估到哪里undefined.

总的来说,这不会像Fisher-Yates Shuffle那样有效,因为你仍然splice是一个阵列.但不同之处在于,您现在只在需要时才开始做这项工作,而不是事先做好,所以根据您的使用情况,这可能会更好.


小智 7

//random number without repetition in JavaScript, Just in one line;
//it can be used as _id;
//it not need to store or check;
Run Code Online (Sandbox Code Playgroud)

//random number without repetition in JavaScript, Just in one line;
//it can be used as _id;
//it not need to store or check;
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢你的想法,但我认为它可能在某些时候匹配,为了更安全,我会使用 const myRnId = (deepness = 10)=&gt; parseInt(Date.now() + Math.random()*deepness) (2认同)

小智 5

function Myrand(max,min){
    arr=[];
    for (i = 0; i < max; i++) {
        x = Math.floor( Math.random() * max) + min;
        if(arr.includes(x) == true){
            i=i-1;
        }else{
            if(x>max==false){
                arr.push(x);
            }
        }
    }
    return arr;
}
console.log(Myrand(5,1));
Run Code Online (Sandbox Code Playgroud)