20

我有以下功能

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

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

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

4

17 回答 17

49

如果我理解正确,那么您只是在寻找数字 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最终将评估为where 。undefined

总体而言,这不会像 Fisher-Yates Shuffle 那样有效,因为您仍在splice处理数组。但不同之处在于,您现在仅在需要时才进行这项工作,而不是预先完成所有工作,因此根据您的用例,这可能会更好。

于 2013-09-14T21:09:05.940 回答
3
//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;

于 2020-03-14T07:05:14.697 回答
3

尝试这个:

var numbers = []; // new empty array

var min, max, r, n, p;

min = 1;
max = 50;
r = 5; // how many numbers you want to extract

for (let i = 0; i < r; i++) {
  do {
    n = Math.floor(Math.random() * (max - min + 1)) + min;
    p = numbers.includes(n);
    if(!p){
      numbers.push(n);
    }
  }
  while(p);
}

console.log(numbers.join(" - "));

于 2021-01-26T20:25:06.833 回答
2
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));
于 2020-05-14T17:24:20.430 回答
2

HTML

<p id="array_number" style="font-size: 25px; text-align: center;"></p>

JS

var min = 1;
var max = 90;
var stop = 6;  //Number of numbers to extract

var numbers = [];

for (let i = 0; i < stop; i++) {
  var n =  Math.floor(Math.random() * max) + min;
  var check = numbers.includes(n);

if(check === false) {
  numbers.push(n);
} else {
  while(check === true){
    n = Math.floor(Math.random() * max) + min;
    check = numbers.includes(n);
      if(check === false){
        numbers.push(n);
      }
    }
  }
}

sort();

 //Sort the array in ascending order
 function sort() {
   numbers.sort(function(a, b){return a-b});
   document.getElementById("array_number").innerHTML = numbers.join(" - ");
}

演示

于 2020-08-24T14:11:42.873 回答
1

问题是当你接近饱和时,你开始花费越来越长的时间来“随机”生成一个唯一的数字。例如,在您上面提供的示例中,最大值为 10。一旦使用的数字数组包含 8 个数字,可能需要很长时间才能找到第 9 个和第 10 个。这可能是产生最大调用堆栈错误的地方。

jsFiddle Demo showing iteration count being maxed

通过在递归内部进行迭代,您可以看到当数组完全饱和但调用函数时会发生大量执行。在这种情况下,函数应该退出。

jsFiddle Demo with early break

if( used.length >= max ) return undefined;

完成迭代检查和无限递归的最后一种方法是这样的jsFiddle Demo

function randomNum(max, used, calls){
 if( calls == void 0 ) calls = 0;
 if( calls++ > 10000 ) return undefined;
 if( used.length >= max ) return undefined;
 var newNum = Math.floor(Math.random() * max + 1);
 if($.inArray(newNum, used) === -1){
   return newNum;
 }else{
   return randomNum(max,used,calls);
 }
}
于 2013-09-14T20:48:34.907 回答
1
<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Math.random()</h2>

<p>Math.random() returns a random number between 0 (included) and 1 (excluded):</p>

<p id="demo"></p>

<script>


var storeArray = []

function callRamdom(){
    var randomNumber = Math.floor(Math.random() * 5);   
    return randomNumber;
}

function randomStore(){ 

    var localValue = callRamdom()
    var status = false;
    for(i=0;i<5; i++){
    var aa = storeArray[i];
        if(aa!=localValue){
            console.log(storeArray[i]+"hhhhh"+ localValue); 
            if(i==4){
                status=true;        
            }

        }   
        else
        break;

    }

    if(status==true){

        storeArray.push(localValue);    
    }
    if(storeArray.length!=5){
        randomStore();
    }   

    return storeArray;
}



document.getElementById("demo").innerHTML = randomStore();


</script>

</body>
</html>
于 2017-09-02T19:58:49.890 回答
1

let arr = [];

do {
  let num = Math.floor(Math.random() * 10 + 1);
  arr.push(num);
  arr = arr.filter((item, index) => {
    return arr.indexOf(item) === index
  });
} while (arr.length < 10);

console.log(arr);

于 2019-09-10T15:26:48.917 回答
1
while(randArr.length < SIZEOFARRAY){
  val = Math.floor((Math.random() * RANGEOFVALUES));

  if(randArr.indexOf(val) < 0){
    randArr.push(val);
  }
}

您可以将SIZEOFARRAY更改为您希望使用的数组的大小,也可以将RANGEOFVALUES更改为您希望随机化的值范围

于 2020-04-21T19:37:42.647 回答
1
const GenerateRandomNumbers = (max) => {
let orderNumbers = new Set();
for (let i = 1;  ;i++){
    let random = Math.floor(Math.random() * max + 1)  ;
    orderNumbers.add(random);
    
    if (orderNumbers.size == max){
        break;
    }
    
    }
    return orderNumbers;}
于 2021-07-26T21:08:48.520 回答
0
function randomNumbers(max) {
    function range(upTo) {
        var result = [];
        for(var i = 0; i < upTo; i++) result.push(i);
        return result;
    }
    function shuffle(o){
        for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
        return o;
    }
    var myArr = shuffle(range(max));
    return function() {
        return myArr.shift();
    };
}

建立了一个小测试,在jsfiddle上试试这个:

var randoms = randomNumbers(10),
    rand = randoms(),
    result = [];
while(rand != null) {
    result.push(rand);
    rand = randoms();
}
console.log(result);

随机播放功能由dzone.com提供。

于 2013-09-14T21:03:33.790 回答
0

这就是我使用underscore.js实现它的方式

从到值获取n整数。论据在哪里。minmaxnsize

var randomNonRepeatingIntFromInterval = function(min, max, size) {
    var values = [];

    while (values.length < size) {
      values.push(Math.floor(Math.random() * ( max - min + 1) + min));

      values = _.uniq(values);
    }

    return values;
  }
于 2017-05-03T21:51:45.957 回答
0

抱歉,这是对旧问题的新答案,但使用地图可以更有效地完成此操作。你所追求的是随机选择而不是非重复随机。非重复随机是荒谬的。

其中 _a 是集合,而 r 不是集合的一部分,我们对随机值 r 进行 lambda:

function aRandom(f){
  var r = Math.random();
  aRandom._a[r] ? aRandom(f) : f(r,aRandom._a[r] = 1);
}
aRandom._a = {};

//usage:
aRandom(function(r){ console.log(r) });

当浏览器运行缓慢时重新定义 aRandom._a。为了避免最终的迟缓,人们应该真正使用具有足够熵的 UUID 生成算法,这样重复的机会实际上是零,而不是暴力强制可微性。我选择函数名 aRandom 是因为拉丁语前缀 A- 的意思是“远离”。由于使用得越多,输出就越远离随机。该函数在 Macbook 上在 2100 毫秒内产生一百万个唯一值。

上述方案的优点是无需限制设置。同样,多个调用者可以同时使用它,并假设它们的值与所有其他调用者不同。这对于诸如保证没有重叠的噪声抖动分布之类的事情很方便。

但是,它也可以修改为返回整数,以便将 ram 的使用限制为提供的长度:

function aRandom(f,c){
  var r = Math.floor(Math.random()*c);
  aRandom._a[r] ? aRandom(f,c) : f(r,aRandom._a[r] = 1);
}
aRandom._a = {};


//usage:
var len = 10;
var resultset = [];
for(var i =0; i< len; i++){
  aRandom(function(r){ resultset.push(r); }, len);
}
console.log(resultset);
于 2017-10-19T05:18:06.670 回答
0

randojs.com使它成为一个简单的单行:

randoSequence(1, 10)

这将按随机顺序返回一个从 1 到 10 的数字数组。您只需将以下内容添加到您的 html 文档的头部,您就可以轻松地随心所欲地做任何您想做的事情。来自数组的随机值、随机的 jquery 元素、来自对象的随机属性,甚至防止重复,正如我在这里展示的那样。

<script src="https://randojs.com/1.0.0.js"></script>
于 2019-12-02T03:03:22.320 回答
0

仅供参考的一种解决方案

const fiveNums = () => {
  const ranNum = () => Math.floor(Math.random() * (10 + 1));
  let current;
  let arr = [];

  while(arr.length < 5) {
    if(arr.indexOf(current = ranNum()) === -1) {
       arr.push(current);
    }
  }
  return arr;
};

fiveNums();
于 2020-02-28T17:12:53.427 回答
0

如果不需要排列和/或长度应该是可变的,这里是一个不重复随机列表/数组的解决方案,没有if 语句:

  1. 随机播放功能:
    • 输入:
      • 任意长度的数组或对象(列表)
      • 可选:要过滤的最后一个键(Array:索引号,List:键的字符串)
    • 输出:
      • 随机密钥
      • 让你的随机物品使用myArrayOrList[key]

// no repeat if old_key is provided
function myShuffle(arr_or_list, old_key = false) {
  var keys = Array.from(Object.keys(arr_or_list)); //extracts keys
  if (old_key != false) {
    keys.splice(keys.indexOf(old_key), 1);  // removes old_key from keys
  };
  var randomKey = keys[Math.floor(Math.random() * keys.length)]; // get random key
  return randomKey;
}

//test:
const a = [10, 20, 30, 40, 50, 60];
const b = {
  "a": 10,
  "bla-bla bla": 20,
  "d": 30,
  "c": 40
};
var oldKeys_a = [];
var oldKeys_b = [];
oldKeys_a[0] = myShuffle(a);
oldKeys_b[0] = myShuffle(b);
var i;
for (i = 1; i < 10; i++) {
  oldKeys_a[i] = myShuffle(a, oldKeys_a[i - 1]);
  oldKeys_b[i] = myShuffle(b, oldKeys_b[i - 1]);
}

alert('oldKeys_a: ' + oldKeys_a + '; oldKeys_b: ' + oldKeys_b)
//random...
//>>> oldKeys_a: 1,3,0,0,5,0,4,5,2,3; oldKeys_b: d,a,d,bla-bla bla,a,c,d,bla-bla bla,a,d <<<

于 2020-04-04T01:30:44.357 回答
-2

你真的不想丢失随机数。真正的随机数必须能够重复。

真正的随机数就像掷骰子。接下来可以出现任何数字。

洗牌的数字就像抽纸牌。每个数字只能出现一次。

你真正要求的是洗牌一个数字列表,然后使用洗牌列表中的第一个这么多数字。

考虑按顺序制作一个数字列表,然后使用随机数生成器从该列表的副本中随机选择一个数字。每次,将选定的数字放在新列表的末尾,然后将其从旧列表的副本中删除,从而缩短该列表。完成后,新列表将包含打乱后的数字,旧列表的副本将为空。

或者,您可以选择选择的号码并立即使用它,通过删除使用的号码来缩短列表的副本。因为您已从列表中删除了该号码,所以它无法再次出现。

于 2016-03-27T09:47:02.110 回答