Math.random 关于数组

Math.random in regards to arrays

我对数组如何与 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/99999 会在位置 6/9 吗?

他们发生了很多所以我会把它分解:

Math.random

你答对了第一部分。 Math.random 将生成一个 >= 0 且 < 1 的数字。Math.random 可以 return 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

数组长度

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

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

更多随机数学

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

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

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

Math.random()

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

* mathematics.length - 1

这个random的目标是生成一个随机数组索引。我们需要从长度中减去 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

我们可以把这段代码放在[]到select数组中的一个项目的随机索引处。

更多信息/来源

  • Random Numbers
  • More solutions

你在看简单的乘法,你的代码中有一个错误。它应该引用数组 'examples' 你是 select 的,而不是你没有提到的东西 'mathematics':

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() returns 介于 0 和 1 之间的数字(它可以 return 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 returns 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

然后你select那个编号的元素:

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

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

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

Math.round() 对比 Math.floor()

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

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

让我们看看 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.5 两倍1.52)。对于三个索引值中的任何一个,我们都有 25% 的机会获得 050% 的机会获得 1,而不是均等的机会2 的概率为 25%。糟糕。

相反,我们需要将 Math.random() 结果乘以 3 的整个数组长度,因此 n>= 0< 3,并且然后 floor 结果: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).

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

Math.random

它returns一个介于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