如何使用JavaScript生成8个1到100之间的唯一随机数?
答案 0 :(得分:126)
var arr = []
while(arr.length < 8){
var r = Math.floor(Math.random()*100) + 1;
if(arr.indexOf(r) === -1) arr.push(r);
}
document.write(arr);
答案 1 :(得分:35)
答案 2 :(得分:13)
生成100个数字的排列,然后按顺序选择。
使用Knuth Shuffle(aka the 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而prob。交换其他92的是92/100。
但是如果我们为完整数组运行算法,那么我们确信(几乎)每个条目都被交换。
否则我们会面临一个问题:选择哪8个数字?
答案 3 :(得分:10)
如果您想避免使用库,上述技术很好,但是如果您对库有好处,我建议您查看Chance以便在JavaScript中生成随机内容。
专门解决您的问题,使用Chance就像以下一样简单:
// 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="http://chancejs.com/chance.min.js"></script>
免责声明,作为Chance的作者,我有点偏颇;)
答案 4 :(得分:8)
为了避免任何漫长而不可靠的洗牌,我会做以下事情......
Voila - 没有重复的数字。
如果有兴趣的话,我可以稍后发布一些实际的代码。
编辑:这可能是我的竞争对手,但是看过@Alsciende的帖子后,我忍不住发布了我承诺的代码。<!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>
答案 5 :(得分:6)
使用Set的现代JS解决方案(和平均情况O(n))
const nums = new Set();
while(nums.size !== 8) {
nums.add(Math.floor(Math.random() * 100) + 1);
}
console.log([...nums]);
&#13;
答案 6 :(得分:3)
我会这样做:
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;
答案 7 :(得分:3)
这是我编写的一个非常通用的函数,用于为数组生成随机唯一/非唯一整数。假设此答案中的最后一个参数为真。
/* 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'是一个非常有用的对象,因为生成的每个随机数将直接检入此tempObj,如果该键已经存在,如果没有,那么我们将i减少一个,因为我们需要1个额外的运行,因为当前随机号已经存在。
在您的情况下,请运行以下
_arrayRandom(8, 1, 100, true);
就是这样。
答案 8 :(得分:2)
将数字从1改为100是正确的基本策略,但如果您只需要8个改组数字,则无需对所有100个数字进行随机播放。
我不太了解Javascript,但我相信很容易快速创建一个包含100个空值的数组。然后,对于8轮,你将数组的第n个元素(n从0开始)与从n + 1到99的随机选择的元素交换。当然,任何未填充的元素都意味着该元素确实已经存在原始索引加1,所以这很简单。当你完成8轮时,阵列的前8个元素将有8个洗牌数字。
答案 9 :(得分:1)
对于像这样的[,2,,4,,6,7,,]
个洞的数组
因为我的问题是填补这些漏洞。所以我根据自己的需要对其进行了修改:)
以下修改后的解决方案对我有用:)
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
答案 10 :(得分:1)
最早的答案是sje397
的答案。你会得到尽可能快的随机数字。
我的解决方案与他的解决方案非常相似。但是,有时你想要随机顺序的随机数,这就是我决定发布答案的原因。另外,我提供了一般功能。
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));
答案 11 :(得分:1)
与The Machine Charmer相同的排列算法,但具有原型实现。更适合大量的选秀权。如果可用,请使用js 1.7 destructuring assignment。
// 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);
编辑: 根据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);
答案 12 :(得分:1)
var arr = []
while(arr.length < 8){
var randomnumber=Math.ceil(Math.random()*100)
if(arr.indexOf(randomnumber) === -1){arr.push(randomnumber)}
}
document.write(arr);
比我见过的其他答案短
答案 13 :(得分:0)
下面是一个示例,它从0到100(包括0和100)之间随机抽取5个数字,且没有重复。
let finals = [];
const count = 5; // Considering 5 numbers
const max = 100;
for(let i = 0; i < max; i++){
const rand = Math.round(Math.random() * max);
!finals.includes(rand) && finals.push(rand)
}
finals = finals.slice(0, count)
答案 14 :(得分:0)
这是Fisher Yates/Durstenfeld Shuffle的实现,但是当拾取大小小于可用元素数量时,没有实际创建数组,从而降低了空间复杂性或所需的内存。
要从100个数字中选择8个数字,不必创建100个元素的数组。
假设创建了一个数组,
rnd
)rnd
如果未创建数组,则可以使用hashMap记住实际的交换位置。当生成的第二个随机数等于先前生成的一个数时,地图将提供该位置的当前值,而不是实际值。
const getRandom_ = (start, end) => {
return Math.floor(Math.random() * (end - start + 1)) + start;
};
const getRealValue_ = (map, rnd) => {
if (map.has(rnd)) {
return getRealValue_(map, map.get(rnd));
} else {
return rnd;
}
};
const getRandomNumbers = (n, start, end) => {
const out = new Map();
while (n--) {
const rnd = getRandom_(start, end--);
out.set(getRealValue_(out, rnd), end + 1);
}
return [...out.keys()];
};
console.info(getRandomNumbers(8, 1, 100));
console.info(getRandomNumbers(8, 1, Math.pow(10, 12)));
console.info(getRandomNumbers(800000, 1, Math.pow(10, 15)));
答案 15 :(得分:0)
这是我拼凑的ES6版本。我敢肯定它可以更巩固一点。
function randomArray(i, min, max) {
min = Math.ceil(min);
max = Math.floor(max);
let arr = Array.from({length: i}, () => Math.floor(Math.random()* (max - min)) + min);
return arr.sort();
}
let uniqueItems = [...new Set(randomArray(8, 0, 100))]
console.log(uniqueItems);
答案 16 :(得分:0)
使用Set
是最快的选择。这是获取使用回调生成器的唯一随机数的通用函数。现在,它快速和可重复使用。
// Get a unique 'anything'
let unique = new Set()
function getUnique(generator) {
let number = generator()
while (!unique.add(number)) {
number = generator()
}
return number;
}
// The generator. Return anything, not just numbers.
const between_1_100 = () => 1 + Math.floor(Math.random() * 100)
// Test it
for (var i = 0; i < 8; i++) {
const aNumber = getUnique(between_1_100)
}
// Dump the 'stored numbers'
console.log(Array.from(unique))
答案 17 :(得分:0)
另一种更简单的方法是生成一个具有100个数字升序的数组并将其随机排序。实际上,这实际上导致了一个非常简短的片段(在我看来)。
function randomNumbers() {
const numbers = [ ...Array(100).keys() ].map(num => num + 1);
numbers.sort(() => Math.random() - 0.5);
return numbers.slice(0, 8);
}
答案 18 :(得分:0)
getRandom (min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
getNRandom (min, max, n) {
const numbers = []
if (min > max) {
return new Error('Max is gt min')
}
if (min === max) {
return [min]
}
if ((max - min) >= n) {
while (numbers.length < n) {
let rand = this.getRandom(min, max + 1)
if (numbers.indexOf(rand) === -1) {
numbers.push(rand)
}
}
}
if ((max - min) < n) {
for (let i = min; i <= max; i++) {
numbers.push(i)
}
}
return numbers
}
答案 19 :(得分:0)
将其实现为生成器使得使用它非常好。注意,这种实现不同于需要首先对整个输入数组进行混洗的实现。
此
sample
功能可以懒惰地工作,每次迭代会为您提供 1 随机项目,直至您要求的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); // f g c
// 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)) // [b c g f d e a]
&#13;
我选择以不改变输入数组的方式实现sample
,但你很容易认为变异实现是有利的。
例如,shuffle
函数可能希望改变原始输入数组。或者您可能希望在不同时间从相同的输入中进行采样,每次都更新输入。
// sample :: Integer -> [a] -> [a]
const sample = n => function* (xs) {
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield xs.splice(i,1)[0];
n--; len--;
}
}
// deal :: [Card] -> [Card]
const deal = xs => Array.from(sample (2) (xs));
// setup a deck of cards (13 in this case)
// cards :: [Card]
let cards = 'A234567890JQK'.split('');
// deal 6 players 2 cards each
// players :: [[Card]]
let players = Array.from(Array(6), $=> deal(cards))
console.log(players);
// [K, J], [6, 0], [2, 8], [Q, 7], [5, 4], [9, A]
// `cards` has been mutated. only 1 card remains in the deck
console.log(cards);
// [3]
&#13;
由于数组输入变异,
sample
不再是纯函数,但在某些情况下(如上所示),它可能更有意义。
我选择生成器而不是仅返回数组的函数的另一个原因是因为您可能希望继续采样直到某些特定条件。
也许我想从1,000,000个随机数列表中得到第一个素数。
因为我们正在使用生成器,所以此任务很简单
const randomPrimeNumber = listOfNumbers => {
for (let x of sample(Infinity) (listOfNumbers)) {
if (isPrime(x))
return x;
}
return NaN;
}
这将一次连续采样1个随机数x
,检查它是否为素数,然后返回x
(如果是)。如果在找到素数之前数字列表已用尽,则返回NaN
。
注意:强>
This answer最初是在另一个问题上分享的,该问题因此复制而被关闭。因为它与这里提供的其他解决方案截然不同,我也决定在这里分享它
答案 20 :(得分:0)
此解决方案使用的散列比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))
答案 21 :(得分:0)
答案 22 :(得分:0)
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之间的数字标记它们。然后我们对这些标记的随机数进行排序,并随机对标签进行混洗。或者,根据这个问题的需要,人们可以取消只找到标记随机数的前8位。找到前8个项目比整个阵列排序便宜。
这里必须注意,排序算法会影响这个算法。如果使用的排序算法是稳定的,则存在轻微的偏差,有利于较小的数字。理想情况下,我们希望排序算法不稳定,甚至不会偏向稳定性(或不稳定性),以产生具有完全均匀概率分布的答案。
答案 23 :(得分:0)
这是我的个人解决方案:
<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之间),然后使用警告框显示它们。
答案 24 :(得分:0)
使用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:试图建议更新维基但它被拒绝了。我仍然认为它可能对其他人有用。
答案 25 :(得分:0)
如果您需要更多唯一身份,则必须生成一个数组(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)=&GT;
[2,77,38,53,63,42,52,22,78,50,39,77,1,88,40,33,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 ]
答案 26 :(得分:0)
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
答案 27 :(得分:0)
如何使用object properties as a hash table?这样,您最好的方案是仅随机化8次。只有你想要一小部分数字才会有效。它比Fisher-Yates的内存密集程度要低得多,因为你不必为数组分配空间。
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的一个特性,所以上面对互联网来说几乎没用。不要害怕,因为我通过添加这样的键功能使ECMAScript 3兼容。
if (typeof keys == "undefined")
{
var keys = function(obj)
{
props=[];
for (k in ht) if (ht.hasOwnProperty(k)) props.push(k);
return props;
}
}
答案 28 :(得分:-1)
您也可以使用这样的一个班轮:
[...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]