生成1到100之间的唯一随机数
我怎样才能生成8,例如,1到100之间的唯一随机数使用JavaScript?
var arr = [] while(arr.length < 8){ var randomnumber = Math.ceil(Math.random()*100) if(arr.indexOf(randomnumber) > -1) continue; arr[arr.length] = randomnumber; } document.write(arr);
- 用数字1到100填充数组。
- 随机播放 。
- 采取结果数组的前8个元素。
生成100个数字的排列 ,然后连续select。
使用Knuth Shuffle(又名Fisher-Yates shuffle)algorithm 。
JavaScript的:
function fisherYates ( myArray,stop_count ) { var i = myArray.length; if ( i == 0 ) return false; int c = 0; while ( --i ) { var j = Math.floor( Math.random() * ( i + 1 ) ); var tempi = myArray[i]; var tempj = myArray[j]; myArray[i] = tempj; myArray[j] = tempi; // Edited thanks to Frerich Raabe c++; if(c == stop_count)return; } }
代码从链接复制。
编辑 :
改进的代码:
function fisherYates(myArray,nb_picks) { for (i = myArray.length-1; i > 1 ; i--) { var r = Math.floor(Math.random()*i); var t = myArray[i]; myArray[i] = myArray[r]; myArray[r] = t; } return myArray.slice(0,nb_picks); }
潜在问题:
假设我们有100个数组(例如[1,2,3 … 100]),我们在8次交换之后停止交换; 那么大部分时间数组将会看起来像{1,2,3,76,5,6,7,8,…这里的数字将被打乱… 10}。
因为每个号码将被交换概率1/100所以概率。 交换前8个号码是8/100,而概率。 交换其他92是92/100。
但是,如果我们运行全数组的algorithm,那么我们确信(几乎)每个条目都被交换。
否则我们会面临一个问题:哪8个号码可供select?
如果你想避免一个图书馆,上面的技巧是好的,但是如果你能和一个图书馆一起工作的话,我build议检查一下在JavaScript中产生随机的东西的机会 。
特别是要解决你的问题,使用机会就像:
// One line! var uniques = chance.unique(chance.natural, 8, {min: 1, max: 100}); // Print it out to the document for this snippet so we can see it in action document.write(JSON.stringify(uniques));
<script src="chance.min.js"></script>
为了避免长时间和不可靠的洗牌,我会做以下…
- 按顺序生成包含1到100之间数字的数组。
- 生成1到100之间的随机数
- 在数组中查找该索引处的数字并存储在结果中
- 从arrays中移除elemnt,使其更短
- 重复步骤2,但使用99作为随机数的上限
- 重复第2步,但使用98作为随机数的上限
- 重复第2步,但使用97作为随机数的上限
- 重复第2步,但使用96作为随机数的上限
- 重复第2步,但使用95作为随机数的上限
- 重复步骤2,但使用94作为随机数的上限
- 重复步骤2,但使用93作为随机数的上限
瞧 – 没有重复的号码。
如果有人感兴趣,我可以稍后发布一些实际的代码。
编辑:这可能是我在竞争中的连胜,但是,看到@Alsciende的post,我忍不住张贴我承诺的代码。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <html> <head> <title>8 unique random number between 1 and 100</title> <script type="text/javascript" language="Javascript"> function pick(n, min, max){ var values = [], i = max; while(i >= min) values.push(i--); var results = []; var maxIndex = max; for(i=1; i <= n; i++){ maxIndex--; var index = Math.floor(maxIndex * Math.random()); results.push(values[index]); values[index] = values[maxIndex]; } return results; } function go(){ var running = true; do{ if(!confirm(pick(8, 1, 100).sort(function(a,b){return a - b;}))){ running = false; } }while(running) } </script> </head> <body> <h1>8 unique random number between 1 and 100</h1> <p><button onclick="go()">Click me</button> to start generating numbers.</p> <p>When the numbers appear, click OK to generate another set, or Cancel to stop.</p> </body>
我会这样做:
function randomInt(min, max) { return Math.round(min + Math.random()*(max-min)); } var index = {}, numbers = []; for (var i=0; i<8; ++i) { var number; do { number = randomInt(1, 100); } while (index.hasOwnProperty("_"+number)); index["_"+number] = true; numbers.push(number); } delete index;
这是我写的一个非常通用的函数,用于为数组生成随机唯一/非唯一整数。 假设这个答案的最后一个参数为true。
/* Creates an array of random integers between the range specified len = length of the array you want to generate min = min value you require max = max value you require unique = whether you want unique or not (assume 'true' for this answer) */ function _arrayRandom(len, min, max, unique) { var len = (len) ? len : 10, min = (min !== undefined) ? min : 1, max = (max !== undefined) ? max : 100, unique = (unique) ? unique : false, toReturn = [], tempObj = {}, i = 0; if(unique === true) { for(; i < len; i++) { var randomInt = Math.floor(Math.random() * ((max - min) + min)); if(tempObj['key_'+ randomInt] === undefined) { tempObj['key_'+ randomInt] = randomInt; toReturn.push(randomInt); } else { i--; } } } else { for(; i < len; i++) { toReturn.push(Math.floor(Math.random() * ((max - min) + min))); } } return toReturn; }
这里的'tempObj'是一个非常有用的obj,因为每个生成的随机数都将直接检查tempObj中是否已经存在,如果不存在,则我们将i减1,因为我们需要额外运行1次,因为当前的随机数已经存在。
在你的情况下,运行以下
_arrayRandom(8, 1, 100, true);
就这样。
将数字从1改为100是正确的基本策略,但如果只需要8个混洗号码,则不需要洗牌所有100个号码。
我不太了解Javascript,但我相信很容易快速创build一个100个空值的数组。 然后,在8轮中,将数组的第n个元素(n从0开始)与从n + 1到99中随机select的元素进行交换。当然,任何尚未填充的元素都意味着该元素真的会原来的索引加1,所以这是微不足道的因素。当你完成8轮,你的数组的前8个元素将有你8个洗牌号码。
与The Machine Charmer相同的排列algorithm,但是具有原型实现。 更适合大量的select。 如果可用,使用js 1.7解构赋值 。
// swaps elements at index i and j in array this // swapping is easy on js 1.7 (feature detection) Array.prototype.swap = (function () { var i=0, j=1; try { [i,j]=[j,i]; } catch (e) {} if(i) { return function(i,j) { [this[i],this[j]] = [this[j],this[i]]; return this; } } else { return function(i,j) { var temp = this[i]; this[i] = this[j]; this[j] = temp; return this; } } })(); // shuffles array this Array.prototype.shuffle = function() { for(var i=this.length; i>1; i--) { this.swap(i-1, Math.floor(i*Math.random())); } return this; } // returns n unique random numbers between min and max function pick(n, min, max) { var a = [], i = max; while(i >= min) a.push(i--); return a.shuffle().slice(0,n); } pick(8,1,100);
编辑:另一个build议,更适合less量的select,基于belugabob的答案。 为了保证唯一性,我们从数组中删除选取的数字。
// removes n random elements from array this // and returns them Array.prototype.pick = function(n) { if(!n || !this.length) return []; var i = Math.floor(this.length*Math.random()); return this.splice(i,1).concat(this.pick(n-1)); } // returns n unique random numbers between min and max function pick(n, min, max) { var a = [], i = max; while(i >= min) a.push(i--); return a.pick(n); } pick(8,1,100);
对于像这样[,2,,4,,6,7,,]
孔的arrays,因为我的问题是填补这些漏洞。 所以我修改它,根据我的需要:)
以下修改后的解决scheme为我工作:)
var arr = [,2,,4,,6,7,,]; //example while(arr.length < 9){ var randomnumber=Math.floor(Math.random()*9+1); var found=false; for(var i=0;i<arr.length;i++){ if(arr[i]==randomnumber){found=true;break;} } if(!found) for(k=0;k<9;k++) {if(!arr[k]) //if it's empty !!MODIFICATION {arr[k]=randomnumber; break;}} } alert(arr); //outputs on the screen
最好的答案是sje397
的答案。 尽可能快地获得尽可能好的随机数。
我的解决scheme与他的解决scheme非常相似。 但是,有时候你会随机select随机数,所以我决定发表一个答案。 另外,我提供一个通用的function。
function selectKOutOfN(k, n) { if (k>n) throw "k>n"; var selection = []; var sorted = []; for (var i = 0; i < k; i++) { var rand = Math.floor(Math.random()*(n - i)); for (var j = 0; j < i; j++) { if (sorted[j]<=rand) rand++; else break; } selection.push(rand); sorted.splice(j, 0, rand); } return selection; } alert(selectKOutOfN(8, 100));
var arr = [] while(arr.length < 8){ var randomnumber=Math.ceil(Math.random()*100) if(arr.indexOf(randomnumber) === -1){arr.push(randomnumber)} } document.write(arr);
比我见过的其他答案短
如何使用对象属性作为哈希表 ? 这样你最好的scheme是只随机8次。 只有当你想要一小部分数字时才有效。 这也比Fisher-Yatesless得多的内存,因为你不必为数组分配空间。
var ht={}, i=rands=8; while ( i>0 || keys(ht).length<rands) ht[Math.ceil(Math.random()*100)]=i--; alert(keys(ht));
然后我发现Object.keys(obj)是ECMAScript 5的一个特性,所以上面在Internet上几乎没有任何用处。 不要害怕,因为我通过添加一个像这样的键函数来使ECMAScript 3兼容。
if (typeof keys == "undefined") { var keys = function(obj) { props=[]; for (k in ht) if (ht.hasOwnProperty(k)) props.push(k); return props; } }
var bombout=0; var checkArr=[]; var arr=[]; while(arr.length < 8 && bombout<100){ bombout++; var randomNumber=Math.ceil(Math.random()*100); if(typeof checkArr[randomNumber] == "undefined"){ checkArr[randomNumber]=1; arr.push(randomNumber); } } // untested - hence bombout
如果你需要更多独特的,你必须生成一个数组(1..100)。
var arr=[]; function generateRandoms(){ for(var i=1;i<=100;i++) arr.push(i); } function extractUniqueRandom() { if (arr.length==0) generateRandoms(); var randIndex=Math.floor(arr.length*Math.random()); var result=arr[randIndex]; arr.splice(randIndex,1); return result; } function extractUniqueRandomArray(n) { var resultArr=[]; for(var i=0;i<n;i++) resultArr.push(extractUniqueRandom()); return resultArr; }
以上代码更快:
extractUniqueRandomArray(50)=> [2,79,38,59,63,42,52,22,78,50,39,77,1,88,40,23,48,84,91,49,4,54 ,93,36,100,82,62,41,89,12,24,31,86,92,64,75,70,61,67,98,76,80,56,90,83,44,43 ,47,7,53]
用JavaScript 1.6的indexOf函数添加另一个更好的版本的相同的代码(接受的答案)。 每次检查重复时,不需要遍历整个数组。
var arr = [] while(arr.length < 8){ var randomnumber=Math.ceil(Math.random()*100) var found=false; if(arr.indexOf(randomnumber) > -1){found=true;} if(!found)arr[arr.length]=randomnumber; }
旧版本的Javascript仍然可以使用顶部的版本
PS:试图build议更新到维基,但它被拒绝。 我仍然认为这可能对其他人有用。
这是我个人的解决scheme:
<script> var i, k; var numbers = new Array(); k = Math.floor((Math.random()*8)); numbers[0]=k; for (var j=1;j<8;j++){ k = Math.floor((Math.random()*8)); i=0; while (i < numbers.length){ if (numbers[i] == k){ k = Math.floor((Math.random()*8)); i=0; }else {i++;} } numbers[j]=k; } for (var j=0;j<8;j++){ alert (numbers[j]); } </script>
它随机生成8个唯一的数组值(0到7之间),然后使用警告框显示它们。
function getUniqueRandomNos() { var indexedArrayOfRandomNo = []; for (var i = 0; i < 100; i++) { var randNo = Math.random(); indexedArrayOfRandomNo.push([i, randNo]); } indexedArrayOfRandomNo.sort(function (arr1, arr2) { return arr1[1] - arr2[1] }); var uniqueRandNoArray = []; for (i = 0; i < 8; i++) { uniqueRandNoArray.push(indexedArrayOfRandomNo[i][0]); } return uniqueRandNoArray; }
我认为这种方法与大多数答案中的方法不同,所以我想我可以在这里添加一个答案(虽然这个问题是在4年前问的)。
我们生成100个随机数,并用1到100之间的数字来标记每个数。然后,我们对这些标记的随机数进行sorting,随机地对标记进行混洗。 或者,根据这个问题的需要,只要find带标签的随机数的前8就可以避免。 find前8个项目比sorting整个arrays便宜。
这里必须注意的是,sortingalgorithm影响这个algorithm。 如果使用的sortingalgorithm是稳定的,那么稍微倾向于偏好较小的数字。 理想情况下,我们希望sortingalgorithm不稳定,甚至没有偏向于稳定性(或不稳定性),以完全一致的概率分布产生答案。
这可以处理生成高达20位UNIQUE随机数
JS
var generatedNumbers = []; function generateRandomNumber(precision) { // input --> number precision in integer if (precision <= 20) { var randomNum = Math.round(Math.random().toFixed(precision) * Math.pow(10, precision)); if (generatedNumbers.indexOf(randomNum) > -1) { if (generatedNumbers.length == Math.pow(10, precision)) return "Generated all values with this precision"; return generateRandomNumber(precision); } else { generatedNumbers.push(randomNum); return randomNum; } } else return "Number Precision shoould not exceed 20"; } generateRandomNumber(1);
的jsfiddle
这个解决scheme使用比O(1)更高性能的哈希,而不是检查是否驻留在数组中。 它也有额外的安全检查。 希望它有帮助。
function uniqueArray(minRange, maxRange, arrayLength) { var arrayLength = (arrayLength) ? arrayLength : 10 var minRange = (minRange !== undefined) ? minRange : 1 var maxRange = (maxRange !== undefined) ? maxRange : 100 var numberOfItemsInArray = 0 var hash = {} var array = [] if ( arrayLength > (maxRange - minRange) ) throw new Error('Cannot generate unique array: Array length too high') while(numberOfItemsInArray < arrayLength){ // var randomNumber = Math.floor(Math.random() * (maxRange - minRange + 1) + minRange) // following line used for performance benefits var randomNumber = (Math.random() * (maxRange - minRange + 1) + minRange) << 0 if (!hash[randomNumber]) { hash[randomNumber] = true array.push(randomNumber) numberOfItemsInArray++ } } return array } document.write(uniqueArray(1, 100, 8))
作为一个发电机来实现这个function使得它可以很好地工作。 注意,这个实现不同于那些需要整个input数组首先被混洗的实现。
这个
sample
函数懒散地工作,每次迭代给你一个随机项目,直到你要求的N
项目。 这很好,因为如果你只想从1000列表中的3个项目,你不必先触及所有1000个项目。
// sample :: Integer -> [a] -> [a] const sample = n => function* (xs) { let ys = xs.slice(0); let len = xs.length; while (n > 0 && len > 0) { let i = (Math.random() * len) >> 0; yield ys.splice(i,1)[0]; n--; len--; } } // example inputs let items = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; // get 3 random items for (let i of sample(3) (items)) console.log(i); // fgc // partial application const lotto = sample(3); for (let i of lotto(numbers)) console.log(i); // 3 8 7 // shuffle an array const shuffle = xs => Array.from(sample (Infinity) (xs)) console.log(shuffle(items)) // [bcgfdea]
你也可以这样做:
[...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]