【问题标题】:Math.random in regards to arraysMath.random 关于数组
【发布时间】:2015-08-13 02:00:34
【问题描述】:

我对数组如何与Math.random() 等函数协同工作感到困惑。既然Math.random()函数选择了一个大于等于0小于1的数,那么数组中的每个变量分配了多少具体的数字呢?例如,在下面的代码中,必须选择什么数字才能打印出1?必须选择什么号码才能打印出jaguar

var examples= [1, 2, 3, 56, "foxy", 9999, "jaguar", 5.4, "caveman"];
var example= examples[Math.round(Math.random() * (examples.length-1))];
console.log(example);

是否为数组中的每个元素分配了等于x/n 的位置编号(x 是相对于第一个元素的位置编号,n 是元素的数量)?由于examples 有9 个元素,1 会在1/9 的位置,9999 会在6/9 的位置吗?

【问题讨论】:

    标签: javascript arrays variables random


    【解决方案1】:

    它们发生了很多事情,所以我会分解它:

    数学.随机

    你说对了第一部分。 Math.random 将生成一个 >= 0 和 Math.random 可以返回 0,但机会几乎是 0 我认为这就像 10^{-16}(你被闪电击中的可能性要高 100 亿倍)。这将产生一个数字,例如:

    0.6687583869788796
    

    让我们停在那里一秒钟

    数组及其索引

    数组中的每一项都有一个索引或位置。范围为 0 - 无穷大。在 JavaScript 中,数组从零开始,而不是从一开始。这是一张图表:

    [ 'foo', 'bar', 'baz' ]
    

    现在索引如下:

    name | index
    -----|------
    foo  | 0
    bar  | 1
    baz  | 2
    

    要从它的索引中获取一个项目,请使用[]

    fooBarBazArray[0]; // foo
    fooBarBazArray[2]; // baz
    

    数组长度

    现在数组长度与最大索引不同。这将是我们计算它的长度。所以上面的数组会返回3。每个数组都有一个 length 属性,其中包含它的长度:

    ['foo', 'bar', 'baz'].length; // Is 3
    

    更多随机数学

    现在让我们看看这个随机化的东西:

    Math.round(Math.random() * (mathematics.length-1))
    

    他们正在发生很多事情。让我们分解一下:

    Math.random()

    所以首先我们生成一个随机数。

    * 数学.length - 1

    这个随机的目标是生成一个随机数组索引。我们需要从长度中减去 1 以获得最高索引。

    第一部分结论

    这给了我们一个从 0 到最大数组索引的数字。在我之前展示的示例数组上:

    Math.random() * (['foo', 'bar', 'baz'].length - 1)
    

    现在他们是一个小问题:

    此代码生成一个介于 0 和长度之间的随机数。这意味着-1 不应该在那里。让我们修复这段代码:

    Math.random() * ['foo', 'bar', 'baz'].length
    

    运行这段代码,我得到:

    2.1972009977325797
    1.0244733088184148
    0.1671080442611128
    2.0442249791231006
    1.8239217158406973
    

    终于

    为了得到随机索引,我们必须把它从一个丑陋的小数变成一个漂亮的整数:Math.floor 基本上会截断小数。

    Math.floor 结果:

    2
    0
    2
    1
    2
    

    我们可以将此代码放在[] 中,以在随机索引处选择数组中的一项。

    更多信息/来源

    【讨论】:

    • "将生成一个 > 0 和 [0; 1) 范围内的数字。
    • 因此,如果我将 '.length' 应用于 Math.random 函数,那么 Math.floor 函数将生成一个大于或等于 0 且小于最大数组索引的数字(在本例中为将小于 3,因为@vihan1086 作为示例给出的代码中有三个变量)。总而言之,使用 .length 和 Math.random 函数将范围从 [0;1) 更改为 [0;3)。这听起来正确吗?
    • @DarienSpringer - 你说得对!请参阅我的答案,了解如何使用 Math.floor() 以及为什么不应该使用 Math.round() 的详细示例。
    • 因此 Math.floor() 创建了 Math.random() 选择数组中任何变量的均等机会,而 Math.round 会创建一些变量更有可能被选择的情况因为 Math.round() 如何确定将调整为哪些数字(某些整数被选中的可能性是其他整数的两倍)。
    • @zerkms - 我冒昧地将其更正为 ">= 0 和
    【解决方案2】:

    您正在查看简单的乘法,以及代码中的错误。它应该引用您从中选择的数组“示例”,而不是您没有提到的称为“数学”的东西:

    var example = examples[Math.round(Math.random() * (examples.length-1))];
                                                         ^^
    

    然后你只是将一个随机数乘以数组中的事物数。所以最大随机数是 1,如果你的数组中有 50 个东西,你将随机数乘以 50,现在最大随机数是 50。

    所有较小的随机数(0 到 1)也被缩放 50 倍,现在从(0 到 50)以大致相同的随机性分布。然后你将它四舍五入到最接近的整数,这是你数组中从 1 到 n 的随机索引,你可以用 element[thatnumber] 来挑选它。

    完整示例:

    Math.random() 返回 0 到 1 之间的数字(它可以返回 0,但这种可能性非常小):

    Math.random()
    0.11506261994225964
    Math.random()
    0.5607304393516861
    Math.random()
    0.5050221864582
    Math.random()
    0.4070177578793308
    Math.random()
    0.6352060229006462
    

    将这些数字乘以某个值以放大它们; 1 x 10 = 10 所以 Math.random() * 10 = 0 到 10 之间的随机数。

    Math.random() *n 返回 0 到 n 之间的数字:

    Math.random() * 10
    2.6186012867183326
    Math.random() * 10
    5.616868671026196
    Math.random() * 10
    0.7765205189156167
    Math.random() * 10
    6.299650241067698
    

    然后Math.round(number) 去掉小数点,留下 1 到 10 之间最接近的整数:

    Math.round(Math.random() * 10)
    5
    

    然后你选择那个编号的元素:

    examples[  Math.round(Math.random() * 10)  ];
    

    而您使用.length-1,因为索引从 0 开始计数并在长度为 1 处结束,(请参阅 @vihan1086 的解释,其中有很多关于数组索引的内容)。

    这种方法不太擅长随机化 - 特别是不太可能选择第一个和最后一个元素。我写这篇文章时没有意识到,但@Michael Geary 的回答要好得多——避免使用 Math.round() 并且不使用 length-1。

    【讨论】:

    • 对不起,Math.round() 并从数组长度中减去 1 是错误的。这不会让您有平等的机会击中每个数组元素。有关详细说明和正确方法,请参阅我的答案。
    • @MichaelGeary 您的回答更均匀随机,总体上更好 - 我没有意识到我在这方面有多么错误。但是您也关注 Darien 说他不关心的位(随机性的质量)并跳过我认为他不理解的更基本的位 - 数组中的每个变量是否占用等量的从大于或等于 0 到小于 1 的长度? - 他缺少关于乘法缩放随机范围的理解,你用 掩盖了它,所以我们将 Math.random() 乘以 2。我已经为你投票并编辑了我。
    【解决方案3】:

    Math.round()Math.floor()

    首先要注意的是:Math.round() 在处理Math.random() 返回的值时永远不是正确的函数。它应该是Math.floor(),然后你不需要length 上的-1 更正。这是因为Math.random() 返回的值是>= 0< 1

    这有点棘手,所以让我们举一个具体的例子:一个包含三个元素的数组。正如vihan1086's excellent answer 解释的那样,这个数组的元素编号为012。要从该数组中选择一个随机元素,您希望获得这三个值中的任何一个的机会均等。

    让我们看看Math.round( Math.random() * array.length - 1 ) 的效果如何。数组长度为3,因此我们将Math.random() 乘以2。现在我们有一个值n,即>= 0< 2。我们将该数字四舍五入到最接近的整数:

    如果n>= 0< .5,则四舍五入为0
    如果n>= .5< 1.5,则四舍五入为1
    如果n>= 1.5< 2,则四舍五入为2

    到目前为止一切顺利。我们有机会获得我们需要的三个值中的任何一个,0、1 或 2。但是 有什么机会呢?

    仔细查看这些范围。中间范围(.51.5)是其他两个范围(0.51.52)的两倍。我们有 25% 的机会获得050% 的机会获得1,以及 25% 的机会获得@987654362,而不是三个索引值中任何一个的机会均等@。哎呀。

    相反,我们需要将Math.random() 的结果乘以3 的整个数组长度,所以n>= 0< 3,然后将结果取平:Math.floor( Math.random() * array.length ) 它的工作原理是这样的:

    如果n>= 0< 1,它会跳转到0
    如果n>= 1< 2,它会下降到1
    如果n>= 2< 3,它会落地到2

    现在我们显然有相同的机会达到012 三个值中的任何一个,因为每个范围的长度相同。

    保持简单

    这里有一个建议:不要在一个表达式中编写所有这些代码。将其分解为不言自明且有意义的简单函数。以下是我喜欢执行此特定任务的方式(从数组中选择一个随机元素):

    // Return a random integer in the range 0 through n - 1
    function randomInt( n ) {
        return Math.floor( Math.random() * n );
    }
    
    // Return a random element from an array
    function randomElement( array ) {
        return array[ randomInt(array.length) ];
    }
    

    那么剩下的代码就直截了当:

    var examples = [ 1, 2, 3, 56, "foxy", 9999, "jaguar", 5.4, "caveman" ];
    var example = randomElement( examples );
    console.log( example );
    

    看看这种方式有多简单?现在,您不必每次想从数组中获取随机元素时都进行数学计算,只需调用 randomElement(array)

    【讨论】:

      【解决方案4】:

      这是一个老问题,但我将提供一个新的、更短的解决方案来从数组中获取随机项。

      数学.随机

      它返回一个介于 0 和 1 之间的数字(1 包括在内)。

      按位不是~

      此运算符的行为返回您提供的相反值,因此:

      a = 5
      ~a // -5
      

      它也忘记了小数,例如:

      a = 5.95
      ~a // -5
      

      它跳过了小数点,所以它的行为类似于 Math.floor(当然不返回负值)。

      双重运算符

      用于强制转换为布尔类型的负逻辑运算符!!!null // false,我们通过双重否定强制它。 如果我们使用相同的想法但对于数字,如果我们这样做,我们会强制一个数字下降:~~5.999 // 5

      因此,

      TLDR;

      getRandom = (arr, len = arr.length) => arr[~~(Math.random() * len)]
      

      示例:

      getRandom([1,2,3,4,5]) // random item between 1 and 5
      

      【讨论】:

        猜你喜欢
        • 2010-12-03
        • 2018-08-22
        • 2011-08-22
        • 2015-01-07
        • 1970-01-01
        • 2016-03-02
        • 1970-01-01
        • 2019-10-18
        相关资源
        最近更新 更多