【问题标题】:A random number between 1 and 4 that's not another random number1 到 4 之间的随机数,不是另一个随机数
【发布时间】:2012-09-21 01:36:47
【问题描述】:

由于某种原因,以下代码不起作用。

var a1 = Math.floor(Math.random()*4+1); 

//Answer2
for(a2 = 0; a2 != a1 && a2 != 0; a2 = Math.floor(Math.random()*4+1)){
    alert(a2);
}

我试图让“a2”成为 1-4 的 int,但不等于“a1”。

怎么了? 提前谢谢!!!

编辑:

感谢大家的帮助! 这是我的最终结果:

var a1, a2;
a1 = Math.floor(Math.random()*4+1); 
a2 = a1;

while(a2 == a1){
        a2 = Math.floor(Math.random() * 3 + 1);
        alert(a2);
}

【问题讨论】:

  • 有什么理由更喜欢Math.floor(x + 1) 而不是Math.ceil(x)?我能想到的唯一原因是Math.random() 的返回结果可能是[0,1)
  • @wim:确实,这就是Math.random() 返回的内容。 Slulego:alert(a2) 不应该在循环之外吗?
  • 我使用 alert(a2) 只是为了跟踪正在发生的事情......(实际上我开始使用 console.log 代替)

标签: javascript math random for-loop


【解决方案1】:

用 while 循环代替怎么样?初始化a2 = a1 然后:

while(a2 == a1) {
    a2 = Math.floor(Math.random() * 4 + 1);
}

【讨论】:

  • 在现有代码中,必须在 a2 的初始化值处进行 0 检查。使用 for 结构,a2 可以/应该使用对 random 的相同调用来初始化,以防止第一次通过循环是保证失败。
  • do 循环怎么样?不要初始化a2 = a1 然后做同样的事情:do { a2 = Math.floor(Math.random() * 4 + 1); } while(a2 === a1);
  • 是的,这是一个更好的建议 .. 来自 python 背景我不知道 javascript 中的 do 循环
【解决方案2】:

您的测试逻辑是颠倒的。当测试为真时,for 循环继续执行,如果失败则不会。而不是:a2 != a1 && a2 != 0 你应该有(a2 == a1) || (a2 == 0)。尽管也请记住,警报也只会在 a2 为无效状态的情况下执行,尽管 for 之后的警报应该是有效的。

或者,如果您正在寻找有趣的数学方式来使用模运算(无需重试):

a2 = (Math.floor(Math.random() * 3 + (a1 + 1)) % 4) || 4

【讨论】:

  • +1 表示“数学方式”。这是一个看起来很吓人的表达式,直到你看到它在做什么:循环计数,从a1 + 1 中随机选择一个数字,直到a1,但不包括a1;最后,把 0 变成 4,因为这个集合不包括 0。
【解决方案3】:

试试这个功能。它会以随机顺序为您提供一个数组,其中包含从 1 到 max 的数字。然后你可以用它来给一个变量赋值,而且它永远不会重复:

编辑:我找到了一种纯粹的功能性方法:

function randomRange(min, max) {
  return (new Array(++max-min))
    .join('.').split('.')
    .map(function(v,i){ return min+i })
    .sort(function(){ return 0|Math.random()*max });
}

console.log(rand(1,4)); //-> [4,2,1,3] random array from 1 to 4

var arr = rand(1,4);
var a = arr[0];
var b = arr[1];
...

编辑 2:上面的内容似乎在某些浏览器上存在问题,请查看Random but just in Chrome 以获得更好的解决方案。

演示: http://jsbin.com/ohohum/1/edit(运行多次查看随机性)

【讨论】:

  • -1 因为动态正则表达式是测试字符串中是否包含某些内容的糟糕方法,而这里完全不需要正则表达式,字符串也是如此。
【解决方案4】:

如果数字大于或等于要排除的数字,只需添加一个:

var a2 = Math.floor(Math.random() * 3 + 1);

if(a2 >= a1) {
    a2++;
}

【讨论】:

  • 好的,但如果它是假的,我需要它再试一次。对不起,我忘了提。
  • @Slulego:“如果它是假的”是什么意思?
  • 另外,为什么要投反对票?这比循环更有效。
  • 我不是反对者,但我并不清楚代码的作用以及它是否会扭曲 a2 的分布(想想贝叶斯定律)
  • @wim:它不会扭曲任何东西。这是歪曲事物的方法:)
【解决方案5】:

a2a1 相同或为零时,您正在选择一个新的a2 值。这是倒退的——你在循环之前将a2 设置为零,所以它永远不会执行。

您需要在a2 为零或等于a1 时循环:

var a1 = Math.floor(Math.random()*4+1); 

//Answer2
for(a2 = 0; a2 == a1 || a2 == 0; a2 = Math.floor(Math.random()*4+1)){
    // nothing here
}   
alert(a2);

【讨论】:

    【解决方案6】:

    有两种标准的方式来做这种事情。不过我正在考虑一个更通用的框架

    过滤列表中的示例

    1. 创建要从中选择的基值数组

      var values = [1,2,3,4]
      
    2. 删除你不感兴趣的值

      values = Array.filter( values, function(x) { return x!=a1; } )
      
    3. 从列表中随机选择一个值

      var a2 = values[Math.floor(Math.random()*values.length)];
      

    使用拒绝抽样

    1. 创建要选择的值数组

       var values = [1,2,3,4]
      
    2. 随机选择一个值,然后重试直到成功

       var a2 =  values[Math.floor(Math.random()*values.length)];
       while( a2==a1 )
       {
         a2 = values[Math.floor(Math.random()*values.length)];
       }
      

    比较

    如果我们认为n 是初始列表的长度,m 是删除元素的数量,那么过滤后的版本会进行n 比较以构建长度为n-m 的过滤列表,但是只有一个随机数生成。相比之下,拒绝方法平均进行n/(n-m) 比较和随机数生成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-23
      • 2014-04-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多