【问题标题】:Generating unique random numbers (integers) between 0 and 'x'在 0 和 'x' 之间生成唯一的随机数(整数)
【发布时间】:2012-01-12 19:30:45
【问题描述】:

我需要生成一组唯一(无重复)整数,并且介于 0 和给定数字之间。

即:

var limit = 10;
var amount = 3;

如何使用 Javascript 生成 1 到 10 之间的 3 个唯一数字?

【问题讨论】:

标签: javascript random


【解决方案1】:

使用基本的Math 方法:

  • Math.random() 返回一个介于 0 和 1 之间的随机数(包括 0,不包括 1)。
  • 将此数字乘以所需的最大数字(例如 10)
  • 将此数字向下舍入到最接近的整数

    Math.floor(Math.random()*10) + 1
    

例子:

//Example, including customisable intervals [lower_bound, upper_bound)
var limit = 10,
    amount = 3,
    lower_bound = 1,
    upper_bound = 10,
    unique_random_numbers = [];

if (amount > limit) limit = amount; //Infinite loop if you want more unique
                                    //Natural numbers than exist in a
                                    // given range
while (unique_random_numbers.length < limit) {
    var random_number = Math.floor(Math.random()*(upper_bound - lower_bound) + lower_bound);
    if (unique_random_numbers.indexOf(random_number) == -1) { 
        // Yay! new random number
        unique_random_numbers.push( random_number );
    }
}
// unique_random_numbers is an array containing 3 unique numbers in the given range

【讨论】:

  • @benhowdle89 在循环中,在变量 random_numbers 中。我先把逻辑放在这里,再放例子。
  • @benhowdle89 有人将您的问题标记为作业。这是真的?如果没有,请删除标签。
  • 不,不是,也不是重复的:(
  • 更改 "Math.random()*(upper_bound - lower_bound + 1)" 删除 + 1,我在 lower_bound = 0,upper_bound = 5 上测试,+ 1 部分我有时得到 6
  • 答案是错误的。不要使用 round() - 使用 floor() 或 ceil() 否则,您的结果将不会均匀分布。例如,如果您想要一个介于 0 和 3 之间的随机整数,并且使用 round(),那么最终得到 1 和 2 的次数将比 0 和 3 的次数多,因为有更多可能的随机值会四舍五入为 1 和 2,因为round() 可以向上或向下舍入。使用 floor 或 ceil 强制浮动始终沿同一方向进行舍入,从而产生更分散的结果。
【解决方案2】:
Math.floor(Math.random() * (limit+1))

Math.random() 生成一个介于 0 和 1 之间的浮点数,Math.floor() 将其向下舍入为整数。

通过将它乘以一个数字,您可以有效地得出0..number-1 的范围。如果您希望在num1num2 的范围内生成它,请执行以下操作:

Math.floor(Math.random() * (num2-num1 + 1) + num1)

要生成更多数字,只需使用 for 循环并将结果放入数组或直接写入文档即可。

【讨论】:

  • 如果我想要一个介于 0 和 5 之间的随机数,这不会产生任何结果 = 0。我在想是因为 + 1 使得最小结果 = 1
  • @paulzag 你说得对,感谢您指出!一个简单的解决方法是将 + 1 移动到 Math.floor 内,但它可能也很少会生成一个高于上限的数字......嗯
  • 我用 num1 = 0 和 num2 = 10 进行了尝试,如果我运行足够多次,它会同时生成 0 和 10。很好的答案 - 谢谢!
  • @Daniel 是的,但问题是它可以超过限制 1,很少见,除了减去可以从 limit+ 中减去的最小浮点单元之外,没有办法解决这个问题1,我对如何做到这一点一无所知。
【解决方案3】:
function generateRange(pCount, pMin, pMax) {
    min = pMin < pMax ? pMin : pMax;
    max = pMax > pMin ? pMax : pMin;
    var resultArr = [], randNumber;
    while ( pCount > 0) {
        randNumber = Math.round(min + Math.random() * (max - min));
        if (resultArr.indexOf(randNumber) == -1) {
            resultArr.push(randNumber);
            pCount--;
        }
    }
    return resultArr;
}

根据需要的范围,返回整数的方法可以更改为:ceil (a,b], round [a,b], floor [a,b), for (a,b ) 就是将 min 与 floor 加 1。

【讨论】:

  • 请记住,这不是均匀分布的。我只是在尝试在 [0,100] 中生成(非唯一)随机数并尝试了您的 Math.round(min + Math.random() * (max - min)) 解决方案时发现了这一点,在测试一百万个生成的数字时,我得到了大约一半的 0 和 @ 987654327@ 与任何其他结果相比。
【解决方案4】:
Math.floor(Math.random()*limit)+1

【讨论】:

    【解决方案5】:
    for(i = 0;i <amount; i++)
    {
        var randomnumber=Math.floor(Math.random()*limit)+1
        document.write(randomnumber)
    }
    

    【讨论】:

    • 你永远不会得到0,我认为这是不正确的
    • @NaturalBornCamper 该问题指定了一个介于 1 和 10 之间的数字。
    【解决方案6】:

    这是另一种确保数字唯一的算法:

    1. 生成一个包含从 0 到 x 的所有数字的数组
    2. 随机排列数组,使元素按随机顺序排列
    3. 选择第一个n

    与生成随机数直到获得唯一的方法相比,这种方法使用更多内存,但运行时间更稳定——保证在有限时间内找到结果。如果上限相对较低或服用量相对较高,这种方法效果更好。

    为了简单起见,我的答案使用了Lodash 库,但您也可以在没有该库的情况下实现上述算法。

    // assuming _ is the Lodash library
    
    // generates `amount` numbers from 0 to `upperLimit` inclusive
    function uniqueRandomInts(upperLimit, amount) {
        var possibleNumbers = _.range(upperLimit + 1);
        var shuffled = _.shuffle(possibleNumbers);
        return shuffled.slice(0, amount);
    }
    

    【讨论】:

    • 是的!运行时间有限的解决方案!
    【解决方案7】:

    类似的东西

    var limit = 10;
    var amount = 3;
    var nums = new Array();
    
    for(int i = 0; i < amount; i++)
    {
        var add = true;
        var n = Math.round(Math.random()*limit + 1;
        for(int j = 0; j < limit.length; j++)
        {
            if(nums[j] == n)
            {
                add = false;
            }
        }
        if(add)
        {
            nums.push(n)
        }
        else
        {
            i--;
        }
    }
    

    【讨论】:

      【解决方案8】:
      var randomNums = function(amount, limit) {
      var result = [],
          memo = {};
      
      while(result.length < amount) {
          var num = Math.floor((Math.random() * limit) + 1);
          if(!memo[num]) { memo[num] = num; result.push(num); };
      }
      return result; }
      

      这似乎有效,并且它不断查找重复项。

      【讨论】:

      • 为了避免无限循环,您应该将while循环中的条件更改为while(result.length &lt; amount &amp;&amp; result.length &lt;= max - 1)
      【解决方案9】:
      /**
       * Generates an array with numbers between
       * min and max randomly positioned.
       */
      function genArr(min, max, numOfSwaps){
        var size = (max-min) + 1;
        numOfSwaps = numOfSwaps || size;
        var arr = Array.apply(null, Array(size));
      
        for(var i = 0, j = min; i < size & j <= max; i++, j++) {
          arr[i] = j;
        }
      
        for(var i = 0; i < numOfSwaps; i++) {
          var idx1 = Math.round(Math.random() * (size - 1));
          var idx2 = Math.round(Math.random() * (size - 1));
      
          var temp = arr[idx1];
          arr[idx1] = arr[idx2];
          arr[idx2] = temp;
        }
      
        return arr;
      }
      
      /* generating the array and using it to get 3 uniques numbers */
      var arr = genArr(1, 10);
      for(var i = 0; i < 3; i++) {
        console.log(arr.pop());
      }
      

      【讨论】:

        【解决方案10】:

        我认为,这是最人性化的方法(使用 while 循环中的 break),我在 cmets 中解释了它的机制。

        function generateRandomUniqueNumbersArray (limit) {
        
            //we need to store these numbers somewhere
            const array = new Array();
            //how many times we added a valid number (for if statement later)
            let counter = 0;
        
            //we will be generating random numbers until we are satisfied
            while (true) {
        
                //create that number
                const newRandomNumber = Math.floor(Math.random() * limit);
        
                //if we do not have this number in our array, we will add it
                if (!array.includes(newRandomNumber)) {
                    array.push(newRandomNumber);
                    counter++;
                }
        
                //if we have enought of numbers, we do not need to generate them anymore
                if (counter >= limit) {
                    break;
                }
            }
        
            //now hand over this stuff
            return array;
        }
        

        如果您需要更少的数字,您当然可以在最后一个“if”语句中添加不同的限制(您的数量),但请确保它小于或等于数字本身的限制 - 否则它将是无限的循环。

        【讨论】:

          【解决方案11】:

          这些答案要么没有给出独特值,要么太长了(甚至添加了一个外部库来完成如此简单的任务)。

          1。生成一个随机数。
          2。如果我们已经有这个随机数,则转到 1,否则保留它。
          3。如果我们没有所需的随机数,则转到 1.

          function uniqueRandoms(qty, min, max){
            var rnd, arr=[];
            do { do { rnd=Math.floor(Math.random()*max)+min }
                while(arr.includes(rnd))
                arr.push(rnd);
            } while(arr.length<qty)
            return arr;
          }
          
          //generate 5 unique numbers between 1 and 10
          console.log( uniqueRandoms(5, 1, 10) );

          ...以及相同功能的压缩版本:

          function uniqueRandoms(qty,min,max){var a=[];do{do{r=Math.floor(Math.random()*max)+min}while(a.includes(r));a.push(r)}while(a.length&lt;qty);return a}

          【讨论】:

            【解决方案12】:

            就像基于 ES6 Set 的另一种可能的解决方案(“arr. that can contain only values only”)。

            使用示例:

            // Get 4 unique rnd. numbers: from 0 until 4 (inclusive):
            getUniqueNumbersInRange(4, 0, 5) //-> [5, 0, 4, 1];
            
            // Get 2 unique rnd. numbers: from -1 until 2 (inclusive):
            getUniqueNumbersInRange(2, -1, 2) //-> [1, -1];
            
            // Get 0 unique rnd. numbers (empty result): from -1 until 2 (inclusive):
            getUniqueNumbersInRange(0, -1, 2) //-> [];
            
            // Get 7 unique rnd. numbers: from 1 until 7 (inclusive):
            getUniqueNumbersInRange(7, 1, 7) //-> [ 3, 1, 6, 2, 7, 5, 4];
            

            实施:

            function getUniqueNumbersInRange(uniqueNumbersCount, fromInclusive, untilInclusive) {
            
                // 0/3. Check inputs.
                if (0 > uniqueNumbersCount) throw new Error('The number of unique numbers cannot be negative.');
                if (fromInclusive > untilInclusive) throw new Error('"From" bound "' + fromInclusive
                    + '" cannot be greater than "until" bound "' + untilInclusive + '".');
                const rangeLength = untilInclusive - fromInclusive + 1;
                if (uniqueNumbersCount > rangeLength) throw new Error('The length of the range is ' + rangeLength + '=['
                    + fromInclusive + '…' + untilInclusive + '] that is smaller than '
                    + uniqueNumbersCount + ' (specified count of result numbers).');
                if (uniqueNumbersCount === 0) return [];
            
            
                // 1/3. Create a new "Set" – object that stores unique values of any type, whether primitive values or object references.
                // MDN - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
                // Support: Google Chrome 38+(2014.10), Firefox 13+, IE 11+
                const uniqueDigits = new Set();
            
            
                // 2/3. Fill with random numbers.        
                while (uniqueNumbersCount > uniqueDigits.size) {
                    // Generate and add an random integer in specified range.
                    const nextRngNmb = Math.floor(Math.random() * rangeLength) + fromInclusive;
                    uniqueDigits.add(nextRngNmb);
                }
            
            
                // 3/3. Convert "Set" with unique numbers into an array with "Array.from()".
                // MDN – https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
                // Support: Google Chrome 45+ (2015.09+), Firefox 32+, not IE
                const resArray = Array.from(uniqueDigits);
                return resArray;
            
            }
            

            当前实施的好处:

            1. 有一个基本的输入参数检查——当范围太小等时你不会得到意外的输出。
            2. 支持负数范围(不仅从0开始),例如。 G。从 -1000 到 500 等随机数。
            3. 预期行为:如果输入范围太小,当前最流行的答案将自行扩展范围(上限)。一个例子:获取 10000 个指定范围从 0 到 10 的唯一数字,由于范围太小需要抛出错误(仅 10-0+1=11 个可能的唯一数字)。但是当前的最佳答案将隐藏范围扩大到 10000。

            【讨论】:

              【解决方案13】:
              const getRandomNo = (min, max) => {
                 min = Math.ceil(min);
                 max = Math.floor(max);
                 return Math.floor(Math.random() * (max - min + 1)) + min; 
              }
              

              此函数返回指定值之间的随机整数。该值不小于 min(如果 min 不是整数,则为大于 min 的下一个整数)并且小于(但不等于)max。 示例

              console.log(`Random no between 0 and 10 ${getRandomNo(0,10)}`)
              

              【讨论】:

              • 这不会像 OP 所要求的那样返回 unique 数字。
              【解决方案14】:

              这是一个简单的单行解决方案:

              var limit = 10;
              var amount = 3;
              
              randoSequence(1, limit).slice(0, amount);
              

              它使用randojs.com 生成一个从 1 到 10 的随机打乱的整数数组,然后切断第三个整数之后的所有内容。如果您想使用此答案,请将其放入 HTML 文档的 head 标记中:

              <script src="https://randojs.com/1.0.0.js"></script>
              

              【讨论】:

              • 嗯,如果它需要 2KB+,118 行(美化) 外部 JS 文件才能工作...否则,按照这种逻辑,如果我们简单地将所有 JS 转储到单独的文件中,任何可能的任务都可能有 "1-line solution"。 (另外,你的答案是 4 行加上文件,而不是 1。)?
              猜你喜欢
              • 2012-04-18
              • 1970-01-01
              • 2011-04-29
              • 2017-02-22
              • 1970-01-01
              • 2017-06-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多