生成1到100之间的唯一随机数


98

如何使用JavaScript 生成1到100之间的一些唯一随机数?


19
并不是真正的骗子,因为它专注于javascript。

2
@dotty好吧,用Java语言执行此操作与使用任何其他语言进行操作之间没有本质区别,但是我不会投票结束。
Pointy 2010年

1
我也不会投票关闭。这足够具体。
乔什·斯托多拉


1
还有另一种更干净的方法可以做到这一点stackoverflow.com/questions/51898200/…–
Huangism

Answers:


173

例如:要生成8个唯一的随机数并将其存储到数组中,只需执行以下操作:

var arr = [];
while(arr.length < 8){
    var r = Math.floor(Math.random() * 100) + 1;
    if(arr.indexOf(r) === -1) arr.push(r);
}
console.log(arr);


15
对于此类问题,实际代码比伪代码好得多;)(删除了我的回答是伪代码...)
Roman Starkov 2010年

3
O可以挑选; 使用var randomnumber = Math.ceil(Math.random()* 100)
Alsciende 2010年

9
-1:该算法是幼稚的方法;这是非常低效的。
Frerich Raabe 2010年

39
哇。天真似乎有点强大。它可能不是最好的解决方案,但它简单,简短,易于理解,并且可以在可接受的操作参数范围内运行,以实现所需的目标。继续下一个任务。完美固然很棒,但“完成”胜于“完美”。
adam0101 2010年

4
该函数有可能在数组中返回0。根据此链接:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…,Math.random()Returns a random number between 0 (inclusive) and 1 (exclusive)。如果the Math.random()偶然返回0,则Math.ceil(0)s也为0,尽管机会很小。
钱琛

43
  1. 用数字1到100填充数组。
  2. 随机播放
  3. 取结果数组的前8个元素。

8
当然,调整代码以仅执行前8个改组会更有效吗?(然后采用半随机排列的数组的最后8个元素)
第二天

1
这也是我一直这样做的方式。因此,如果我想从文件中随机插入十行代码,则可以这样做randlines file | head -10
tchrist 2012年

1
我认为这是正确的答案,因为它保持了概率偏差,而公认的答案却没有
robertotomás17

2
如果N = 10 ^ 12怎么办?不是很有效。
Shinzou

2
在现实世界中,@ shinzou不会使用JavaScript对10 ^ 12的数字进行排序。一个关于问题的问题要求一个简单的答案。我不是在这里解决世界饥饿。我有足够的能力做到这一点,但这不是问题所在。
ЯegDwight

14

生成100个数字的排列,然后顺序选择。

使用Knuth Shuffle(又名Fisher-Yates shuffle)算法

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。

但是,如果我们针对完整数组运行算法,则可以确保(几乎)每一项都被交换。

否则,我们将面临一个问题:要选择哪个8个数字?


5
这种方法是正确的,但不是最优的:由于只需要八个随机数,您可以在八次交换后停止改组。上面的代码交换整个数组(在这种情况下为100个元素)。
Frerich Raabe 2010年

该代码可能会严重改进。返回值,副作用和函数用法都确实使IMO模糊。也许如果您使用fisherYates函数编写的函数能够准确地回答原始问题,那将更加清晰。
Alsciende'3

1
答案已使用改进的代码进行了更新。另外,@ Frerich Raabe:提到了八次交换后停止的问题。
Pratik Deoghare 2010年

您的Fisher-Yates算法错误。r应该取决于i。见我anwser:stackoverflow.com/questions/2380019/...
Alsciende

抱歉,我的可怕错误!!您的实现很酷。喜欢它。+1。如果有其他问题,请告诉我。谢谢。
Pratik Deoghare 2010年

11

使用Set的现代JS解决方案(以及平均情况O(n))

const nums = new Set();
while(nums.size !== 8) {
  nums.add(Math.floor(Math.random() * 100) + 1);
}

console.log([...nums]);


为什么是O(n)?它不能循环任意时间吗?
安东尼·威瑟

@AnthonyWieser你是对的,最坏的情况。我暗示的是一般情况,因为Set.add为o(1)
Alister

我认为这可能会返回0,就像我的答案在更改为使用之前所习惯的那样Math.floor(Math.random()*100) + 1
adam0101 '18

Set在JS中发现很酷!但是,这种解决方案会不会导致不必要的数字生成,直到一个满足唯一性要求,尤其是在最后一次迭代中,如果8接近100呢?因此,我认为我更喜欢sort下面的答案。
Gilad Barner

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的作者,我有点偏颇;)


投票是因为我之前从未看过运行代码片段
2014年

如果我想为优惠券创建一个代码(8个随机字母数字字符串),该代码必须是唯一的,那么如何使用Chance.js来完成?注:优惠券将根据需要进行,所以代码的数量将是不确定的
奥斯卡Yuandinata

@OscarYuandinata很简单,只要var codes = chance.unique(chance.string, 8)您需要从特定字符池中提取的代码,就可以这样指定:chance.unique(chance.string, 8, {pool: "abcd1234"})其中abcd1234可以是池中想要的任何字符。参见偶然机会js.com/#string
维克多·奎因

@VictorQuinn,对不起,我没有说清楚。我的意思是优惠券代码将是8个字符的随机字母数字字符串,而不是8个随机字母数字字符串的数组。哈哈哈..
奥斯卡Yuandinata 2015年

哦,@ OscarYuandinata容易得多chance.string({ length: 8 }),如果您只希望某些字符出现在该字符串中,chance.string({ pool: 'abcd1234', length: 8 })则它将从字符abcd1234返回一个随机的8个字符串,例如“ 2c2c44bc”或“ 331141cc”
Victor Quinn

8

为了避免长时间不可靠的洗牌,我将执行以下操作...

  1. 依次生成一个数组,其中包含1到100之间的数字。
  2. 产生1到100之间的随机数
  3. 在数组中此索引处查找数字并存储在结果中
  4. 从数组中删除元素,使其更短
  5. 从第2步开始重复,但是使用99作为随机数的上限
  6. 从第2步开始重复,但是使用98作为随机数的上限
  7. 从第2步开始重复,但是使用97作为随机数的上限
  8. 从第2步开始重复,但使用96作为随机数的上限
  9. 从第2步开始重复,但使用95作为随机数的上限
  10. 从第2步开始重复,但使用94作为随机数的上限
  11. 从第2步开始重复,但是使用93作为随机数的上限

瞧-没有重复的数字。

如果有人感兴趣,我可能会在以后发布一些实际代码。

编辑:这可能是我的竞争优势,但是在看完@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>


但是,您的第八个数字是1到92之间的随机数,而不是1到100。如果您必须选择90个数字,那么您的最后一个数字只能是1到10,不是吗?
adam0101 2010年

@ adam0101不,因为他在选择数字时会删除它们。因此,在第5步中,他的数组中只有99个数字。@belugabob您没有Knuth Shuffle更有效率。事实上,接头可能是更昂贵的比洗牌(这是完全可靠的)
Alsciende

@ adam0101:他正在从数组中删除选定的元素(请参阅上面的步骤4),从而避免任何元素被选择两次。然后,他将下一个上限用于下一个随机数,这仅仅是因为数组较短。
Frerich Raabe

@Alsciende,是的-认为会有一种方法可以通过改组更有效地执行此操作,但并不确定。为了避免从数组中删除该项,只需将数组中的最后一个条目(假设不是您选择的那个)复制到您选择的位置。
belugabob 2010年

1
不减少values.length的原因是,不能保证减少数组的长度不会通过重新分配内存来完成。使用maxIndex具有相同的效果,因为它们无关紧要,因此只需忽略数组中的最后一个条目即可。
belugabob

8

另一种方法是生成一个100个具有升序编号的数组并将其随机排序。这实际上导致了一个非常简短的片段(在我看来)。

const numbers = Array(100).fill().map((_, index) => index + 1);
numbers.sort(() => Math.random() - 0.5);
console.log(numbers.slice(0, 8));


这是我所有人最喜欢的答案。邓诺(Dunno)为什么只有6票。优雅且具有良好的复杂性(提供sort的实现很好,我敢肯定)。
Gilad Barner

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;

3

这是我编写的非常通用的函数,用于为数组生成随机的唯一/非唯一整数。假定在这种情况下该答案的最后一个参数为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次。

您的情况下,请运行以下命令

_arrayRandom(8, 1, 100, true);

就这样。


如果我想包含0,会发生什么?该行将min = (min) ? min : 1,始终返回1。(因此永远不会选择0)
TBE

很好的一点。:)。谢谢,我已经进行了适当的更改。如果你在一个0通过将现在回到甚至
kaizer1v

2

将数字从1改到100是正确的基本策略,但是如果您只需要8个改组的数字,则无需对所有100个数字进行改组。

我不太了解Javascript,但是我相信快速创建100个null数组很容易。然后,在8个回合中,将数组的第n个元素(n从0开始)与从n + 1到99的随机选择的元素交换。当然,任何未填充的元素都意味着该元素实际上已经原始索引加1,因此可以忽略不计。完成8回合后,数组的前8个元素将具有8个随机数字。


2
var arr = []
while(arr.length < 8){
  var randomnumber=Math.ceil(Math.random()*100)
  if(arr.indexOf(randomnumber) === -1){arr.push(randomnumber)}  
}
document.write(arr);

比我见过的其他答案短


1

与The Machine Charmer相同的置换算法,但具有原型实现。更适合大量选秀权。使用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);

编辑:基于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);

很好的递归实现-我在回答中发布了一个不使用拼接的替代方法,因为我认为这是可以避免的性能
下降

您的解决方案是聪明,但我不会用它在我的阵列#挑方法,因为我不希望有它的元素抛去,当我返回。
Alsciende

您不希望改组哪个数组,原始的1-100数组或结果?前者无所谓,因为它是一个有效的数组,而后者根据代码的性质无论如何都会以随机顺序出现。不太确定我了解您的原因。
belugabob 2010年

原来的一个。我实现了一个通用的Array#pick方法,该方法非常有用。此函数不知道是否是一个有效的数组。是通用,它不会改变这个超过必要的。
Alsciende 2010年

但是它仍然可以改变它,即使只有很小的改变,使用这种技术也是无法避免的。
belugabob 2010年

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

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));

1

这是我拼凑的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);


0

如何将对象属性用作哈希表?这样,最好的情况是只随机化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;
  }
}

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

0

如果需要更多唯一性,则必须生成一个array(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]


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仍可以使用顶部的版本

附言:试图建议对Wiki进行更新,但遭到拒绝。我仍然认为这可能对其他人有用。


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之间),然后使用警报框显示它们。


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个项目比对整个数组进行排序要便宜。

这里必须注意,排序算法会影响该算法。如果使用的排序算法是稳定的,则偏向于较小的数字。理想情况下,我们希望排序算法不稳定,甚至不偏重于稳定性(或不稳定性),以产生具有完全一致的概率分布的答案。


0

最多可以处理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


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))

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]

我选择以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]

sample由于数组输入突变,它不再是函数,但在某些情况下(如上所示),它可能更有意义。


我选择生成器而不是仅返回数组的函数的另一个原因是,您可能要继续采样直到某些特定条件。

也许我想要1,000,000个随机数列表中的第一个素数。

  • “我应该采样多少?” –您不必指定
  • “我必须先找到所有素数,然后选择一个随机素数吗?” - 不。

因为我们正在使用发电机,所以此任务很简单

const randomPrimeNumber = listOfNumbers => {
  for (let x of sample(Infinity) (listOfNumbers)) {
    if (isPrime(x))
      return x;
  }
  return NaN;
}

这将一次连续采样一个随机数x,检查其是否为质数,然后返回x为质数。如果在找到素数之前已用尽数字列表,NaN则返回。


注意:

此答案最初是在另一个问题上共享的,该问题已作为该问题的重复而关闭。由于它与此处提供的其他解决方案非常不同,因此我决定在此处也共享


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
}

0

使用a 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))


0

这是Fisher Yates / Durstenfeld Shuffle的一种实现 ,但是当拾取大小与可用元素数量相比较小时,无需实际创建数组,从而降低了空间复杂性或所需的内存。

要从100个数字中选择8个数字,就不必创建100个元素的数组。

假设创建了一个数组,

  • 从数组(100)的末尾获得rnd1到100之间的随机数()
  • 交换100和随机数 rnd
  • 对数组重复步骤1(99)

如果未创建数组,则可以使用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)));


0

这是一个从5到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)

-1

您也可以像这样用一根衬纸来做:

[...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]


为了不分配任何东西。
MarcinKról18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.