【问题标题】:Generate unique random numbers between 1 and 100生成 1 到 100 之间的唯一随机数
【发布时间】:2011-01-23 17:08:25
【问题描述】:

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

【问题讨论】:

  • 并不是真正的骗子,因为它专注于 javascript。
  • @dotty 好吧,在 Javascript 中执行此操作与使用任何其他语言执行此操作没有本质区别,但我不会投票结束。
  • 我也不会投票关闭。这已经足够具体了。
  • 还有另一种更简洁的方法可以做到这一点stackoverflow.com/questions/51898200/…

标签: javascript random integer numbers


【解决方案1】:

例如:要生成 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)
  • -1:这个算法是幼稚的方法;效率很低。
  • 哇。天真的好像有点强。它可能不是最好的解决方案,但它简单、简短、易于查看正在发生的事情,并且在可接受的操作参数内运行以完成需要完成的任务。继续下一个任务。完美是伟大的,但“完成”比“完美”更好。
  • 函数有可能在数组中返回 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,但几率很低。
【解决方案2】:
  1. 用数字 1 到 100 填充数组。
  2. Shuffle it
  3. 获取结果数组的前 8 个元素。

【讨论】:

  • 确实将代码调整为仅执行前 8 次随机播放会更有效吗? (然后取半洗牌数组的最后8个元素)
  • 这也是我一贯的做法。因此,如果我想从一个包含一堆行的文件中随机抽取十行,我会使用randlines file | head -10
  • 我认为是正确的答案,因为它保持了概率分布,而接受的答案却没有
  • 如果 N=10^12 会怎样?效率不高。
  • @shinzou 在现实世界中,您不会使用 JavaScript 对 10^12 个数字进行排序。一个琐碎的问题需要一个琐碎的答案。我不是来解决世界饥饿问题的。我有能力做到这一点,但这不是问题所在。
【解决方案3】:

使用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)
  • 我认为这可能会像我以前的答案一样返回 0,然后再改为使用 Math.floor(Math.random()*100) + 1
  • 在 JS 中发现 Set 非常酷!但是,如果 8 接近 100,在满足唯一性要求之前,这种解决方案是否会导致不必要的数字生成,尤其是在最后一次迭代中?因此,我认为我更喜欢下面sort 的优雅答案。
【解决方案4】:

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

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

【讨论】:

  • 这是我最喜欢的答案。不知道为什么它只有 6 票。优雅且具有良好的复杂性(前提是sort 实现得很好,我确信它是)。
  • 这是我使用了一段时间的方法,但它有一个问题,因为您经常会得到“伪随机数组”,这些数组已经在某些部分进行了分组和排序。但是有办法改进它。
【解决方案5】:

生成 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;

   }
}

CODE COPIED FROM LINK.

编辑

改进的代码:

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 个数字组成的数组{e.g. [1,2,3...100]} 我们在 8 次交换后停止交换; 那么大多数时间数组看起来像 {1,2,3,76,5,6,7,8,...这里的数字将被打乱...10}。

因为每个数字都会以 1/100 的概率交换,所以 概率。交换前 8 个数字的概率是 8/100,而概率。交换其他 92 是 92/100。

但是,如果我们为完整数组运行算法,那么我们确定(几乎)每个条目都被交换了。

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

【讨论】:

  • 这种方法是正确的,但不是最理想的:你可以在八次交换后停止洗牌,因为你只需要八个随机数。上面的代码交换了整个数组(在这种情况下,100 个元素)。
  • 代码可以大大改进。返回值、副作用和函数使用都非常模糊 IMO。也许如果您使用您的fisherYates函数编写一个完全回答原始问题的函数,它会更清楚。
  • 用改进的代码更新了答案。另外,@Frerich Raabe:提到了八次交换后停止的问题。
  • 您的 Fisher-Yates 算法是错误的。 r 应该取决于 i。看我的回答:stackoverflow.com/questions/2380019/…
  • 哎呀对不起我的可怕错误!你的实现很酷。喜欢它。 +1。如果还有其他问题,请告诉我。谢谢。
【解决方案6】:

如果您想避免使用库,上述技术很好,但取决于您是否可以使用库,我建议您查看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));
&lt;script src="http://chancejs.com/chance.min.js"&gt;&lt;/script&gt;

免责声明,作为 Chance 的作者,我有点偏见;)

【讨论】:

  • 赞成,因为我之前从未见过运行代码 sn-p
  • 如果我想为优惠券制作一个代码(8 个随机字母数字字符串),它必须是唯一的,我该如何使用 Chance.js?注意:优惠券将按需制作,因此代码数量不限
  • @OscarYuandinata 这很简单,只需执行var codes = chance.unique(chance.string, 8) 如果您需要从特定字符池中提取代码,您可以这样指定:chance.unique(chance.string, 8, {pool: "abcd1234"}) 其中 abcd1234 可以是您想要的任何字符水池。见chancejs.com/#string
  • @VictorQuinn,对不起,我没有说清楚。我的意思是优惠券代码将是 8 个字符的随机字母数字字符串,而不是 8 个随机字母数字字符串的数组。哈哈哈..
  • 哦@OscarYuandinata,这要容易得多,嘿chance.string({ length: 8 }),如果您只希望某些字符出现在该字符串中,chance.string({ pool: 'abcd1234', length: 8 }) 将从字符 abcd1234 返回一个随机的 8 个字符串,例如“2c2c44bc”或“331141cc”
【解决方案7】:

为避免任何冗长且不可靠的随机播放,我会执行以下操作...

  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 不,因为他在选择数字时会删除它们。所以在第 5 步中,他的数组中只有 99 个数字。 @belugabob 你并不比 Knuth Shuffle 更有效率。事实上,拼接可能比随机播放更昂贵(这是完全可靠的)
  • @adam0101:他正在从数组中删除选择的元素(参见上面的步骤 4),从而避免任何元素被选择两次。然后他为下一个随机数使用了一个下限,仅仅是因为数组更短。
  • @Alsciende,是的 - 认为使用随机播放可以更有效地执行此操作,但不完全确定。为了避免从数组中删除项目,只需将数组中的最后一个条目(假设它不是您选择的那个)复制到您选择的位置。
  • 不减少 values.length 的原因是不能保证减少数组的长度不是通过重新分配内存来完成的。使用 maxIndex 具有相同的效果,只需忽略数组中的最后一个条目,因为它们变得无关紧要。
【解决方案8】:

我会这样做:

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;

【讨论】:

    【解决方案9】:

    这是我编写的一个非常通用的函数,用于为数组生成随机唯一/非唯一整数。假设此答案的最后一个参数在此场景中为真。

    /* 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)
    • 一个很好的观点。 :)。谢谢,我已经进行了适当的更改。即使您传入 0,它现在也会返回。
    【解决方案10】:

    从 1 到 100 的数字洗牌是正确的基本策略,但如果您只需要 8 个洗好的数字,则无需洗牌所有 100 个数字。

    我不太了解 Javascript,但我相信快速创建一个包含 100 个空值的数组很容易。然后,在 8 轮中,您将数组的第 n 个元素(n 从 0 开始)与从 n+1 到 99 的随机选择的元素交换。当然,任何尚未填充的元素都意味着该元素实际上是原始索引加 1,因此很容易考虑。当您完成 8 轮后,数组的前 8 个元素将有 8 个随机数字。

    【讨论】:

      【解决方案11】:
      var arr = []
      while(arr.length < 8){
        var randomnumber=Math.ceil(Math.random()*100)
        if(arr.indexOf(randomnumber) === -1){arr.push(randomnumber)}  
      }
      document.write(arr);
      

      比我见过的其他答案短

      【讨论】:

        【解决方案12】:

        将其实现为生成器使其非常好用。请注意,此实现不同于需要首先打乱整个输入数组的实现。

        这个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;
        }
        

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


        注意:

        This answer 最初是在另一个问题上共享的,该问题作为该问题的副本而关闭。因为它与这里提供的其他解决方案非常不同,所以我决定在这里也分享一下

        【讨论】:

          【解决方案13】:

          var numbers = [];
          
          for (let i = 0; i < 8; i++) {
            let a = true,
                n;
            while(a) {
              n = Math.floor(Math.random() * 100) + 1;
              a = numbers.includes(n);
            }
            numbers.push(n);
          }
          
          console.log(numbers);

          【讨论】:

            【解决方案14】:

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

            【讨论】:

            • 很好的递归实现 - 我在我的回答中发布了一个不使用拼接的替代方案,因为我觉得这是一个可以避免的性能损失(并不是说 OP 有任何性能问题)
            • 您的解决方案很聪明,但我不会在我的 Array#pick 方法中使用它,因为我不希望 this 在我返回它时让它的元素乱序.
            • 不想洗牌哪个数组,原来的1-100数组还是结果?前者无关紧要,因为它是一个工作数组,而后者根据代码的性质,无论如何都会以随机顺序出现。不太确定我是否理解您的原因。
            • 原版。我实现了一个通用的 Array#pick 方法,我觉得它很有用。这个函数不知道 this 是否是一个工作数组。为了通用,它不会对 this 进行不必要的更改。
            • 但它仍然会改变它,即使只是一点点,这在使用这种技术时是不可避免的。
            【解决方案15】:

            对于像这样[,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
            

            【讨论】:

              【解决方案16】:

              较早的最佳答案是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));
              

              【讨论】:

                【解决方案17】:

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

                【讨论】:

                  【解决方案18】:

                  使用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;
                    }
                  }
                  

                  【讨论】:

                    【解决方案19】:
                    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
                    

                    【讨论】:

                      【解决方案20】:

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

                      【讨论】:

                        【解决方案21】:

                        使用 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:尝试建议对 wiki 进行更新,但被拒绝。我仍然认为它可能对其他人有用。

                        【讨论】:

                          【解决方案22】:

                          这是我个人的解决方案:

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

                          【讨论】:

                            【解决方案23】:
                            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 个项目比对整个数组进行排序更便宜。

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

                            【讨论】:

                              【解决方案24】:

                              这可以处理生成多达 20 位的唯一随机数

                              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

                              【讨论】:

                                【解决方案25】:

                                此解决方案使用哈希,它比检查是否驻留在数组中具有更高的 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))
                                

                                【讨论】:

                                  【解决方案26】:

                                  你也可以像这样用一个衬里做到这一点:

                                  [...((add, set) =&gt; add(set, add))((set, add) =&gt; set.size &lt; 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]

                                  【讨论】:

                                  • 为了不分配任何东西的纯粹性。
                                  【解决方案27】:
                                  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
                                  }
                                  

                                  【讨论】:

                                    【解决方案28】:

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

                                    【讨论】:

                                      【解决方案29】:

                                      这是Fisher Yates/Durstenfeld Shuffle,但没有实际创建阵列,从而减少所需的空间复杂性或内存,当拾取大小与可用元素数量相比。

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

                                      假设创建了一个数组,

                                      • 从数组(100)的末尾,得到1到100的随机数(rnd)
                                      • 交换100和随机数rnd
                                      • 使用数组 (99) 重复步骤 1

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

                                      【讨论】:

                                        【解决方案30】:

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

                                        【讨论】:

                                          猜你喜欢
                                          • 2016-09-25
                                          • 1970-01-01
                                          • 2014-04-11
                                          • 1970-01-01
                                          • 2014-04-02
                                          • 2020-11-02
                                          • 1970-01-01
                                          相关资源
                                          最近更新 更多