【问题标题】:JavaScript generate random number except some valuesJavaScript 生成除某些值外的随机数
【发布时间】:2014-12-10 16:45:14
【问题描述】:

我通过调用generateRandom() 生成从 1 到 20 的随机数。如何排除某些值,例如 8 和 15?

function generateRandom(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

var test = generateRandom(1, 20)

【问题讨论】:

  • 如果是8或15,再调用一次。

标签: javascript


【解决方案1】:

要生成 1 到 20 之间的随机数,不包括某些给定的数字,您可以这样做:

function generateRandom(min, max, exclude) {
  let random;
  while (!random) {
    const x = Math.floor(Math.random() * (max - min + 1)) + min;
    if (exclude.indexOf(x) === -1) random = x;
  }
  return random;
}
const test = generateRandom(1, 20, [8, 15]);

【讨论】:

    【解决方案2】:

    它应该是 or 而不是 and

    function generateRandom(min, max) {
        var num = Math.floor(Math.random() * (max - min + 1)) + min;
        return (num === 8 || num === 15) ? generateRandom(min, max) : num;
    }
    
    var test = generateRandom(1, 20)

    【讨论】:

    • 我已经尝试过这个解决方案,当递归太深时它会停止在浏览器中工作。浏览器阻止代码继续循环。此外,对于移动解决方案(我现在正在测试的)甚至是一个大问题。我更喜欢@Bathsheba 的建议或随机减去/添加一个数字。
    • 函数 generateRandom(min, max,depth) { if(depth>10) { return 1; } var num = Math.floor(Math.random() * (max - min + 1)) + min;返回 (num === 8 || num === 15) ? generateRandom(min, max,depth+1) : 数; } var test = generateRandom(1, 20,0)
    【解决方案3】:

    保持生成器的统计属性的一种方法是在 [1, 18] 中生成一个数字。然后按以下顺序申请:

    1. 如果数字大于等于8,则加1。

    2. 如果数字大于等于15,则加1。

    我不愿意拒绝和重新采样,因为这会导致相关平原出现在线性同余生成器中。

    【讨论】:

    • 这意味着 9 和 16 的返回频率是其他数字的两倍。不知道 OP 是否关心...
    • 不,它没有。请注意,我说的是“以及更多”。试试看。
    • 不清楚每一步后需要重新核对号。例如,如果我得到 14,那么我需要检查它是否 >=8,然后加 1,然后检查新数字 (15) 如果它 >=15 而不是原始数字 (14)。除此之外,这是一个很好的方法,可以推广:let rand = generateRandom(0, 100-optionsToSkip.length); for(let opt of optionsToSkip) { if(rand >= opt) rand+=1; }
    【解决方案4】:
        /**
        * Returns a random integer between min (inclusive) and max (inclusive).
        * Pass all values as an array, as 3rd argument which values shouldn't be generated by the function.
        * The value is no lower than min (or the next integer greater than min
        * if min isn't an integer) and no greater than max (or the next integer
        * lower than max if max isn't an integer).
        * Using Math.round() will give you a non-uniform distribution!
        */
        
    function getRandomInt(min, max) {
       const minimum = Math.ceil(min);
       const maximum = Math.floor(max);
    
       return Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
    }
    
    
    function getRandomIntExcludingExistingNumbers(min, max, excludeArrayNumbers) {
      let randomNumber;
    
      if(!Array.isArray(excludeArrayNumbers)) {
        randomNumber = getRandomInt(min, max);
        return randomNumber;
      }
    
      do {
        randomNumber = getRandomInt(min, max);
      } while ((excludeArrayNumbers || []).includes(randomNumber));
    
      return randomNumber;
    }
    

    const randomNumber = getRandomIntExcludingExistingNumbers(1, 10, [1, 2, 4, 5, 9]);

    // 它将返回 1 到 10 之间的随机整数,不包括 1,2,4,5,9

    解释:

    getRandomInt 函数生成介于最小值和最大值之间的随机数。

    我正在利用该函数创建“getRandomIntExcludingExistingNumbers”函数以避免特定值。

    我们将简单地调用 getRandomInt(min, max) 值。 然后在 do while 循环中,我们将检查随机生成的值是否属于任何不应生成的值。

    如果它是唯一的整数排除值之外,那么我们将返回该值。

    如果我们的值来自排除值,那么从 do --while 循环中,我们将再次调用 getRandomInt 来生成新值。

    【讨论】:

    • 请不要在没有解释的情况下发布代码作为答案。尝试解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
    • 感谢您指出@zsolt-meszaros 的解释。这是我的第一个答案。
    【解决方案5】:

    这是一个稍作修改的答案,与所有其他答案相似,但它允许您传递一个或一组失败的数字

    function generateRandom(min, max, failOn) {
        failOn = Array.isArray(failOn) ? failOn : [failOn]
        var num = Math.floor(Math.random() * (max - min + 1)) + min;
        return failOn.includes(num) ? generateRandom(min, max, failOn) : num;
    }
    

    【讨论】:

      【解决方案6】:

      现在我正在使用它,它不会导致浏览器出现无限循环问题,也在移动设备中进行了测试(使用 Ionic/Cordova):

      function getRandomIndex(usedIndexs, maxIndex) {
          var result = 0;
          var min = 0;
          var max = maxIndex - 1;
          var index = Math.floor(Math.random()*(max-min+1)+min);
      
          while(usedIndexs.indexOf(index) > -1) {
              if (index < max) {
                  index++;
              } else {
                index = 0;
              }
          }
      
          return index;
      }
      

      【讨论】:

        【解决方案7】:

        你可以使用递归函数

        function generateRandom(min, max, num1, num2) {
            var rtn = Math.floor(Math.random() * (max - min + 1)) + min;
            return rtn == num1 || rtn == num2 ? generateRandom(min, max, num1, num2) : rtn;
        }
        

        【讨论】:

          【解决方案8】:

          我认为应该是这样的,如果你想在所有数字上都有良好的分布。 并且,对于此解决方案,要求最大值高于 15,最小值低于 8

          function generateRandom(min, max) {
              var v =  Math.floor(Math.random() * (max - min + 1 - 2)) + min;
              if (v == 8) return max-1;
              else if (v == 15) return max-2;
              else return v;
          }
          
          var test = generateRandom(1, 20)
          

          【讨论】:

          • 'else's are not required here ^^
          • 我不明白。我应该返回值吗?
          • 'return' 打破了函数的实际作用域(它们返回值),所以 else 关键字在这种情况下是无用的^^,我的评论仅供参考
          • 啊,我明白了:) 是的,它可以用也可以不用。我只想写一个属性 if 块。
          • Idk,但“max-2”对我来说并不随机;
          【解决方案9】:

          您可以动态构建数组。取决于您从哪里获得排除的数字。比如:

          var excluded = [8, 15];
          var random = [];
          for(var i = min; i <= max; i++) {
            if(excluded.indexOf(i) !== -1) {
              random.push(i);
            }
          }
          

          然后使用此帖子答案中的提示:How can I generate a random number within a range but exclude some?。应该能带你去你想去的地方。

          【讨论】:

            【解决方案10】:

            这是一个非常愚蠢的过于复杂的解决方案......

                    <script>
                var excludedNumbers = [];
                excludedNumbers.push(8);
                excludedNumbers.push(15);
                excludedNumbers.push(10);
            
                var array = generateExclude(excludedNumbers, 1, 20);
            
                function generateExclude(excludedNumbers, min, max){
                    var newNumbers = [];
                    for(var i = min; i <= max; i++) {
                        for(var j = 0; j < excludedNumbers.length; j++) {
                            var checker = $.inArray(i, excludedNumbers)
                            if(checker > -1){
            
                            }else{
                                if($.inArray(i, newNumbers)<= -1){
                                    newNumbers.push(i); 
                                }
            
                            }
                        };
                    };
                    return newNumbers;
                }
                function generateRandomNumbers(items){
                    var num = items[Math.floor(Math.random()*items.length)];;
                    return num;
                }
                console.log(generateRandomNumbers(array))
                </script>
            

            【讨论】:

              【解决方案11】:

              我已经为 Java 回答了一个类似的问题:Generate random numbers except certain values。我只是将答案复制并粘贴如下。

              实际上,我们不需要将contains(random) 与while 循环一起使用。

              为了简化问题,让我们看看如果我们只有一个排除值会发生什么。我们可以将结果拆分为2 部分。那么可能值的数量是range-1。如果随机数小于排除值,则返回它。否则,我们可以添加1

              对于多个排除值,我们可以将结果集拆分为size+1部分,其中size表示排除值的个数。那么可能值的数量是range-size。然后我们按升序对排除值进行排序。如果随机数小于排除值减去i,那么我们只返回随机数加上i,其中i是排除值的索引。

              public int generateRandomNumberWithExcepts(int start, int end, List<Integer> excepts) {
                  int size = excepts.size();
                  int range = end - start + 1 - size;
                  int randNum = random.nextInt(range) + start;
                  excepts.sort(null); // sort excluding values in ascending order
                  int i=0;
                  for(int except : excepts) {
                      if(randNum < except-i){
                          return randNum + i;
                      }
                      i++;
                  }
                  return randNum + i;
              }
              

              【讨论】:

                【解决方案12】:

                我已经阅读了所有这些答案,它们在哲学上存在很大差异,所以我想我可能会添加我自己的 2 位,尽管这个问题有答案,因为我确实认为有一个更好、更优雅解决这个问题的方法。

                我们可以制作一个函数,以 min、max 和 blacklist 作为参数,并在不使用递归的情况下输出随机结果(并且 if 语句接近 0):

                const blrand = function(min, max, blacklist) { if(!blacklist) blacklist = [] let rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; let retv = 0; while(blacklist.indexOf(retv = rand(min,max)) > -1) { } return retv; }

                用法: let randomNumber = blrand(0, 20, [8, 15]);

                【讨论】:

                  【解决方案13】:

                  你可以这样做

                  function generatedRandExclude(showed,max) {
                       let randNo = -1;
                       while(showed.length < max) {
                          	randNo = Math.floor(Math.random() * Math.floor(max));	
                           	if(!showed.includes(randNo)) {
                              	showed.push(randNo);
                               	break;
                            }
                       }
                       return randNo;
                  }
                  
                  let showed = [];
                  function run() {
                      console.log(generatedRandExclude(showed,6));
                  }
                  run();
                  run();
                  run();
                  run();

                  generatedRandExclude 生成使用数组showed排除的随机数。

                  【讨论】:

                    【解决方案14】:

                    这是一个简单而巧妙的想法,我是一名机电工程师,我正在学习 JS。 这将打印 1 到 100 之间的随机数。 除了 8 和 15

                     var r;   // this is the random integer.
                     var val; //this will serve as validator for the random integer.
                    
                     val=0; 
                     while(val==0)    {
                     r=Math.round(Math.random()*100)+1;
                     if(r!=8 && r!=15){val=1;}    //a valid number will be any number different from 8 and 15
                                                  //then validator will change and go out from the loop.
                                    }   
                    document.write(r);
                    

                    【讨论】:

                      【解决方案15】:

                      您可以使用已排序(升序)数组对大于或等于零的随机值进行偏移,并返回带有调整后随机值的总和。

                      const
                          getRandomWithoutZero = (lower, upper, gaps) => () => {
                              const r = Math.floor(Math.random() * (upper - lower + 1 - gaps.length) + lower);
                              return gaps.reduce((s, g) => s + (s >= g), r);
                          },
                          random = getRandomWithoutZero(-9, 9, [-3, 0, 4]),
                          count = {};
                      
                      for (let i = 0; i < 1.6e6; i++) {
                          const r = random();
                          count[r] = (count[r] || 0) + 1;
                      }
                      
                      console.log(count);
                      .as-console-wrapper { max-height: 100% !important; top: 0; }

                      【讨论】:

                        猜你喜欢
                        • 2013-02-02
                        • 2020-12-11
                        • 1970-01-01
                        • 2013-10-27
                        • 2016-03-10
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-09-10
                        • 2013-10-17
                        相关资源
                        最近更新 更多