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/9
而 9999
会在位置 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
.
这有点棘手,所以让我们举一个具体的例子:一个包含三个元素的数组。正如 所解释的那样,该数组的元素编号为 0
、1
和 2
。对于此数组中的 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。但是 有多少机会?
仔细观察这些范围。中间范围(.5
到 1.5
)是其他两个范围(0
到 .5
的 两倍, 1.5
到 2
)。对于三个索引值中的任何一个,我们都有 25% 的机会获得 0
、50% 的机会获得 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
。
现在我们显然有相同的机会命中三个值 0
、1
或 2
中的任何一个,因为每个范围的长度都相同。
保持简单
这里有一个建议:不要将所有这些代码写在一个表达式中。将其分解为不言自明且有意义的简单功能。以下是我喜欢执行此特定任务的方式(从数组中随机选择一个元素):
// 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
我对数组如何与 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
吗?
他们发生了很多所以我会把它分解:
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
.
这有点棘手,所以让我们举一个具体的例子:一个包含三个元素的数组。正如 0
、1
和 2
。对于此数组中的 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。但是 有多少机会?
仔细观察这些范围。中间范围(.5
到 1.5
)是其他两个范围(0
到 .5
的 两倍, 1.5
到 2
)。对于三个索引值中的任何一个,我们都有 25% 的机会获得 0
、50% 的机会获得 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
。
现在我们显然有相同的机会命中三个值 0
、1
或 2
中的任何一个,因为每个范围的长度都相同。
保持简单
这里有一个建议:不要将所有这些代码写在一个表达式中。将其分解为不言自明且有意义的简单功能。以下是我喜欢执行此特定任务的方式(从数组中随机选择一个元素):
// 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