【问题标题】:Random number generator without dupes in Javascript?Javascript中没有欺骗的随机数生成器?
【发布时间】:2010-09-26 06:12:20
【问题描述】:

我需要帮助来编写一些代码,该代码将从 12 个数字的数组中创建一个随机数并打印 9 次而不会被欺骗。这对我来说很难完成。有什么想法吗?

【问题讨论】:

    标签: javascript random


    【解决方案1】:
    var nums = [1,2,3,4,5,6,7,8,9,10,11,12];
    var gen_nums = [];
    
    function in_array(array, el) {
       for(var i = 0 ; i < array.length; i++) 
           if(array[i] == el) return true;
       return false;
    }
    
    function get_rand(array) {
        var rand = array[Math.floor(Math.random()*array.length)];
        if(!in_array(gen_nums, rand)) {
           gen_nums.push(rand); 
           return rand;
        }
        return get_rand(array);
    }
    
    for(var i = 0; i < 9; i++) {
        document.write(get_rand(nums));
    }
    

    【讨论】:

    • 问题:如何将这个脚本重复20次?
    【解决方案2】:

    执行此操作的最有效和最有效的方法是将您的号码随机排列,然后打印前九个号码。使用good shuffle algorithm。Thilo 的建议会给你带来糟糕的结果。 See here.

    编辑 下面是一个简短的 Knuth Shuffle 算法示例:

    
    void shuffle(vector<int> nums)
    {
      for (int i = nums.size()-1; i >= 0; i--)
      {
        // this line is really shorthand, but gets the point across, I hope.
        swap(nums[i],nums[rand()%i]);
      }
    }
    

    【讨论】:

    • 如果认真对待,使用您建议的经过验证的算法似乎是一个更好的主意。我只想指出,我建议的算法并不是“见这里”中讨论的不利的算法。
    • 这不是同一个算法,不。但我担心如果我理解正确,它仍然会产生同样的错误。您的算法有 n^3 个结果将落在 n!盒子。这不能给出均匀分布。用你的算法尝试文章中的实验,看看它是否有效。
    • 在您链接的博客的 cmets 中,“我的”算法是由“fabio”提出的。他声称它有效,但交换次数更多(不仅仅是数组大小)。我会多读一点,看看我能不能证明它是对还是错。下面 Andrew Dunn 的提议在统计上似乎也是正确的,尽管它存在性能问题。
    • 我看了你指出的那条评论。我还是觉得路径数必须能被n整除!均匀地融入 n!结果,但我可能弄错了。我很想看看你发现将 Knuth 的算法与你的算法并排比较。是的,邓恩的算法应该可以工作(尽管性能)。
    • 我把它带给统计学家:stats.stackexchange.com/questions/3082/…
    【解决方案3】:

    试试这个:

    //Here o is the array;
    var testArr = [6, 7, 12, 15, 17, 20, 21];
        shuffle = function(o){ //v1.0
                            for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
                            return o;
                    };
    shuffle(testArr);
    

    【讨论】:

      【解决方案4】:

      这做起来相对简单,其原理是创建另一个数组来跟踪您使用了数组的哪些元素。

      var tempArray = new Array(12),i,r;
      for (i=0;i<9;i++)
          {
          r = Math.floor(Math.random()*12);    // Get a random index
          if (tempArray[r] === undefined)      // If the index hasn't been used yet
              {
              document.write(numberArray[r]);  // Display it
              tempArray[r] = true;             // Flag it as have been used
              }
          else                                 // Otherwise
              {
              i--;                             // Try again
              }
          }
      

      其他方法包括改组数组、从数组中删除使用的元素或将使用的元素移动到数组的末尾。

      【讨论】:

      • 不要将上面的代码用于专业工作,这是一个非常简单的示例,用于演示您尝试执行的操作背后的逻辑(从 12 个值的数组中随机打印 9 个值)顺序)。
      • 不过,它似乎确实产生了一个无偏的数字序列。我能看到的唯一问题是性能,因为找到剩余数字变得越来越困难。
      • 没错,虽然该算法适用于较小的数据集,但对于较大的数据集,您需要确保不会发生冲突,方法是从数组中删除数据,或者将其推送到末尾.
      【解决方案5】:

      如果我理解正确的话,你想重新排列你的数组。

      循环几次(数组的长度应该这样做),并且在每次迭代中,获取两个随机数组索引并在那里交换两个元素。 (更新:如果你真的很认真,这可能不是best algorithm)。

      然后您可以打印前九个数组元素,它们将按随机顺序排列,不会重复。

      【讨论】:

        【解决方案6】:

        这是一种获取 min 和 max 之间不重复随机数的通用方法:

        function inArray(arr, el) {
            for(var i = 0 ; i < arr.length; i++) 
                    if(arr[i] == el) return true;
            return false;
        }
        
        function getRandomIntNoDuplicates(min, max, DuplicateArr) {
            var RandomInt = Math.floor(Math.random() * (max - min + 1)) + min;
            if (DuplicateArr.length > (max-min) ) return false;  // break endless recursion
            if(!inArray(DuplicateArr, RandomInt)) {
               DuplicateArr.push(RandomInt); 
               return RandomInt;
            }
            return getRandomIntNoDuplicates(min, max, DuplicateArr); //recurse
        }
        

        致电:

        var duplicates  =[];
        for (var i = 1; i <= 6 ; i++) { 
            console.log(getRandomIntNoDuplicates(1,10,duplicates));
        }
        

        【讨论】:

          【解决方案7】:
          const nums = [1,2,3,4,5,6,7,8,9,10,11,12];
          for(var i = 1 ; i < 10; i++){
              result = nums[Math.floor(Math.random()*nums.length)];
              const index = nums.indexOf(result);
              nums.splice(index, 1);
              console.log(i+' - '+result);
          }
          

          【讨论】:

          • 社区encourages 在代码旁边添加解释,而不是纯粹基于代码的答案。正如here 所解释的那样:“虽然此代码可能会回答问题,但提供有关 为什么 和/或 如何 此代码回答问题的附加上下文会提高其长期价值。 "
          猜你喜欢
          • 2019-01-24
          • 1970-01-01
          • 1970-01-01
          • 2021-06-01
          • 2013-05-03
          • 1970-01-01
          • 2022-08-15
          相关资源
          最近更新 更多