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

IT技术 javascript random integer numbers
2021-01-19 06:22:36

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

6个回答

例如:要生成 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);

O 可以采摘;使用 var randomnumber=Math.ceil(Math.random()*100)
2021-03-10 06:22:36
-1:这个算法是幼稚的方法;这是非常低效的。
2021-03-15 06:22:36
对于此类问题,实际代码比伪代码要好得多;)(删除了我的伪代码答案......)
2021-03-22 06:22:36
该函数有可能在数组中返回 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)则也为 0,但几率很小。
2021-03-30 06:22:36
哇。天真似乎有点强。它可能不是最好的解决方案,但它简单、简短、易于查看正在发生的事情,并且在可接受的操作参数内运行以完成需要完成的工作。进入下一个任务。完美是伟大的,但“完成”比“完美”要好。
2021-04-07 06:22:36
  1. 用数字 1 到 100 填充数组。
  2. 洗牌吧
  3. 取结果数组的前 8 个元素。
如果 N=10^12 呢?效率不高。
2021-03-14 06:22:36
这也是我经常这样做的方式。因此,如果我想要一个包含一堆行的文件中的十个随机行,我会这样做randlines file | head -10
2021-03-24 06:22:36
@shinzou 在现实世界中,您不会使用 JavaScript 对 10^12 个数字进行排序。一个琐碎的问题需要一个微不足道的答案。我不是来解决世界饥饿问题的。我有能力做到这一点,但这不是问题的所在。
2021-03-29 06:22:36
我认为是正确的答案,因为它保持了概率分布,而接受的答案没有
2021-04-03 06:22:36
将代码调整为仅进行前 8 次洗牌肯定会更有效吗?(然后取半混洗数组的最后8个元素)
2021-04-07 06:22:36

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

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

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

Set在 JS 中发现非常酷但是,在满足唯一性要求之前,这种解决方案不会导致不必要的数字生成,尤其是在最后一次迭代中,如果 8 更接近于 100?因此,我想我更喜欢sort下面同样优雅的答案
2021-03-11 06:22:36
我认为这可能会返回 0,就像我的答案在更改为使用之前一样 Math.floor(Math.random()*100) + 1
2021-03-15 06:22:36
为什么是 O(n)?它不能循环任意时间吗?
2021-04-05 06:22:36
@AnthonyWieser 你是对的,最坏的情况。我是在暗示平均情况,因为 Set.add 是 o(1)
2021-04-08 06:22:36

另一种方法是生成一个 100 项的数组,并随机排序。这实际上导致了一个非常短且(在我看来)简单的片段。

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

这是我最喜欢的答案。不知道为什么它只有 6 票。优雅且具有良好的复杂性(前提sort是实施得很好,我敢肯定)。
2021-03-25 06:22:36
这是我使用了一段时间的方法,但它有一个问题,因为你经常会得到“伪随机数组”,它已经在某些部分对项目进行了分组和排序。但是有一种方法可以改进它。
2021-04-09 06:22:36

生成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 个号码?

你的 Fisher-Yates 算法是错误的。r 应该取决于 i。看我的回答:stackoverflow.com/questions/2380019/...
2021-03-16 06:22:36
这种方法是正确的,但并不理想:您可以在 8 次交换后停止洗牌,因为您只需要 8 个随机数。上面的代码交换了整个数组(在这个场景中,100 个元素)。
2021-03-17 06:22:36
使用改进的代码更新了答案。另外,@Frerich Raabe:提到了在八次交换后停止的问题。
2021-03-19 06:22:36
可以认真改进代码。返回值、副作用和函数使用都是非常模糊的 IMO。也许如果您编写一个函数来准确回答原始问题,使用您的 fisherYates 函数,它会更清楚。
2021-03-21 06:22:36
哦,对不起,我犯了一个可怕的错误!!你的实现很酷。喜欢它。+1。如果还有什么问题,请告诉我。谢谢。
2021-03-27 06:22:36