你如何在JavaScript的Y和Z范围之间随机生成X个数字?

时间:2010-12-04 13:53:45

标签: javascript jquery

例如,我想在1&之间生成5个唯一数字。 10.结果应该是1到10的5个数字(例如2 3 4 8 10)。

3 个答案:

答案 0 :(得分:6)

  1. 使用您的值范围填充数组
  2. 随机播放阵列
  3. 选择前5个元素
  4. 如果范围非常大,并且您想要的值的数量非常小(例如,1 ... 1000000范围内的5个不同值),那么您可以尝试在范围内生成随机数并扔掉(不太可能重复,直到你有5.“继续尝试”的方法的问题是,你可以花很多时间使用一串随机值,给你很多重复。对于大范围的价值观而言,除非软件给创伤患者提供氧气,否则它可能不值得冒险。

答案 1 :(得分:3)

另一种方法是生成随机数并仅将其添加到 返回的数组,如果它还没有包含它们。

function randomRange(from, to, leng){
    var tem, A= [], L= 0, i= 0;
    randomRangeLoop: 
    while(L< leng){
        tem= Math.floor(Math.random()*to)+from;
        i= 0;
        while(i<L){
            if(A[i++]=== tem) continue randomRangeLoop;
        }
        A[L++]= tem;
    }
    return A;
}

警告(randomRange(1,10,5))

/ *返回值:(数组) 8,6,1,3,5 * /

答案 2 :(得分:2)

function generateNumbers(resultCount, from, to) {
  var result = []; // holds the final result
  var isAlreadyPicked = []; // quick lookup for the picked numbers
  // holds substitutes for when we pick a number that has been picked before
  var substitutes = []; 

  for (var i = 0; i < resultCount; i++) {
    // pick a random number
    var number = Math.floor(Math.random() * (to - from)) + from;  

    if(isAlreadyPicked[number]) {
      // pick a number from the ones we skipped at the end of the range.
      var j = Math.floor(Math.random() * substitutes.length);
      number = substitutes[j];
      substitutes.splice(j, 1);
    }

    // Save the number and mark it as being picked.
    result.push(number);
    isAlreadyPicked[number] = true;

    // decrease the range. (Because there is 1 less number to choose from)
    to -= 1;

    if(!isAlreadyPicked[to]) {
      // Save a substitute for when we pick the same number in a next iteration.
      substitutes.push(to);
    }    
  }

  return result;
}

通过每次迭代减少范围的顶部来工作。如果在结果中已经存在上一次迭代中拾取的数字,只需将其更改为我们离开该范围的顶部数字之一(之前将始终只有1个未被选中的数字)。这也是一个真正的随机数,因为它实际上存在于前一次迭代中选取的数字的位置。

在我看来,这是最好的     解决方案因为:

  1. 它没有分配大量内存 通过将所有数字分配给数组 并洗牌那个数组。

  2. 它只有X次迭代所以挂钩它 直到这台呼吸机:)

  3. 这是真的随机,我以前 回答我在哪里添加1号码 已经被选中了没有。因为 数字后面的数字 这是之前选择的 迭代获得挑选的几率是其他数字的两倍。

  4. 编辑1:我在大量案例中测试了这个算法,我犯了一个小错误。有一个边缘情况,有时数字不是唯一的。它发生在该范围中的一个顶部数字已经被选中时。我更新了我的代码。

    编辑2:如果你感兴趣:这是我用来测试的代码:

    function test(cases, size) {
      var errors = 0;
      for (var i = 0; i < cases; i++) {      
        var start = Math.floor(Math.random() * size);
        var end = start + Math.floor(Math.random() * size);
        var count = Math.floor(Math.random() * (end - start));
    
        var nrs = generateNumbers(count, start, end);
    
        console.log('testing', start, end, count, nrs);
    
        test:
        for (var j = 0; j < count; j++) {
          var testedNumber = nrs[j];
          if(testedNumber < start || testedNumber >= end) {
            console.error('out of range', testedNumber);
            errors += 1;
            break test;
          }
          for (var k = 0; k < count; k++) {
            if(j !== k && nrs[k] === testedNumber) {
              console.error('picked twice', testedNumber);
              errors += 1;
              break test;
            }
          }
        }
      }
    
      console.log('all tests finished | errors:', errors)
    }
    test(1000, 20);
    

    编辑3: Pointy建议使用更快的算法来查看数字是否唯一。我用他/她的建议更新了样本。谢谢Pointy!

    编辑4:通过删除内部循环并将其替换为替换数组,使算法更有效。有趣的是,这个算法实际上可以用作前一个答案中的改组算法:)

    这个问题让我很感兴趣。我以前需要这样的算法。这实际上是我第一次找到满足我的解决方案。我对这个主题进行了一些研究,这似乎是Fisher-Yates shuffle算法的变体。

    编辑5:更改算法以从替代品中挑选一个随机数而不是第一个。