Arrays 为什么这个随机散列值选择器第一次总是返回相同的值';这叫什么?

Arrays 为什么这个随机散列值选择器第一次总是返回相同的值';这叫什么?,arrays,perl,hash,Arrays,Perl,Hash,在试图理解随机散列值选择的工作原理时,我注意到了一些奇怪的事情 通过反复调用下面的Perl脚本,我始终发现返回的第一个结果是相同的。随后返回的值是随机的: use strict; use warnings; use 5.010; my %hash = map { $_ => ord $_ } 'a' .. 'z'; say( (@_=%hash)[1|rand@_] ) for 1 .. 10; # First value always 119 有趣的是,以下内容并未受到

在试图理解随机散列值选择的工作原理时,我注意到了一些奇怪的事情

通过反复调用下面的Perl脚本,我始终发现返回的第一个结果是相同的。随后返回的值是随机的:

use strict;
use warnings;
use 5.010;

my %hash = map { $_ => ord $_ } 'a' .. 'z';

say( (@_=%hash)[1|rand@_] ) for 1 .. 10;       # First value always 119
有趣的是,以下内容并未受到此问题的影响:

sub random_value { ( @_ )[ 1 | rand @_ ] }

say random_value %hash for 1 .. 10;            # First value is random
删除对
@
的引用也可以解决此问题:

say( (%hash)[1|rand keys %hash] ) for 1 .. 10; # First value is random
这已经在Windows(ActivePerl 5.14.2)上进行了测试

表面上看,设置似乎与此有关,但我不确定。有人能解释一下这里发生了什么吗


编辑 我以为这个问题一直到现在才得到回答。为什么arrayref表单没有遇到上面讨论的相同问题

[@_=%hash]->[1|rand@_] for 1 .. 10;            # First value is random

我怀疑在第一次循环迭代中没有定义
@
的竞态条件

say( (@_=%hash)[1|rand@_] ) for 1 .. 10; 
将成为

say( (@_=%hash)[1|rand ()] ) for 1 .. 10; 
因为
@
是一个预先声明的变量,所以它会转义
警告。你会注意到:

say( (my @a=%hash)[1|rand@a] ) for 1 .. 10;   
将崩溃并烧掉,因为postscript中未定义
@a

更新:

[@_=%hash]->[1|rand@_] for 1 .. 10;    

没有什么不同。在赋值的同一语句中使用变量仍然是一种不好的做法。我猜,不同之处在于优先级有所改变,因此首先计算赋值。

没有竞争条件,或者与@uu是否“定义”有关,只是操作顺序问题

列表切片的索引在切片列表之前进行计算。(文档并不能保证这一点或那一点。)所以在第一次迭代中,@u为空,rand的参数为1|0(=0)。从历史上看,rand(0)的行为与rand(1)类似,尽管现在记录为可能发生变化。因此,第一次迭代的索引是>=0和<1,通过索引的隐式int取为0

数组元素获取(
[@\%hash]->[1|rand@_]
)不会遇到类似的问题,因为它在数组操作数之后计算索引。数组片(
@{[@@@hash]}[1|rand@_]
),另一方面,其行为与列表片段相同

比较:

列表切片:

$ perl -MO=Concise,-exec -e'(@_=%hash)[1|rand@_]'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark s
4  <$> const[IV 1] s
5  <#> gv[*_] s
6  <1> rv2av[t7] sK/1
7  <1> rand[t8] sK/1
8  <2> bit_or[t9] sK
9  <0> pushmark s
a  <0> pushmark s
b  <#> gv[*hash] s
c  <1> rv2hv[t4] lK/1
d  <0> pushmark s
e  <#> gv[*_] s
f  <1> rv2av[t2] lKRM*/1
g  <2> aassign[t5] lKS/COMMON
h  <2> lslice vK/2
i  <@> leave[1 ref] vKP/REFC
-e syntax OK
$perl-MO=简明,-exec-e'(@@@hash)[1|rand@_]'
1进入
2下一状态(主1-e:1)v:{
3个pushmark s
4常数[IV 1]s
5 gv[*.]s
6 rv2av[t7]sK/1
7兰特[t8]sK/1
8位_或[t9]sK
9个图章
图章
b gv[*散列]s
c rv2hv[t4]lK/1
d图什马克s
e gv[*Us]
f rv2av[t2]lKRM*/1
g aassign[t5]lKS/普通
h lslice vK/2
我留下[1参考]vKP/REFC
-e语法正常
阵列切片:

$ perl -MO=Concise,-exec -e'@{[@_=%hash]}[1|rand@_]'
1  <0> enter 
2  <;> nextstate(main 2 -e:1) v:{
3  <0> pushmark s
4  <$> const[IV 1] s
5  <#> gv[*_] s
6  <1> rv2av[t8] sK/1
7  <1> rand[t9] sK/1
8  <2> bit_or[t10] sK
9  <0> pushmark s
a  <0> pushmark s
b  <#> gv[*hash] s
c  <1> rv2hv[t4] lK/1
d  <0> pushmark s
e  <#> gv[*_] s
f  <1> rv2av[t2] lKRM*/1
g  <2> aassign[t5] lKS/COMMON
h  <@> anonlist sK*/1
i  <1> rv2av[t6] sKR/1
j  <@> aslice vK
k  <@> leave[1 ref] vKP/REFC
-e syntax OK
$perl-MO=简明,-exec-e'{[@\=%hash]}[1|rand@_]'
1进入
2下一状态(主2-e:1)v:{
3个pushmark s
4常数[IV 1]s
5 gv[*.]s
6 rv2av[t8]sK/1
7兰特[t9]sK/1
8位_或[t10]sK
9个图章
图章
b gv[*散列]s
c rv2hv[t4]lK/1
d图什马克s
e gv[*Us]
f rv2av[t2]lKRM*/1
g aassign[t5]lKS/普通
h anonlist sK*/1
i rv2av[t6]sKR/1
阿斯利克
k离开[1参考]vKP/REFC
-e语法正常
数组元素:

$ perl -MO=Concise,-exec -e'[@_=%hash]->[1|rand@_]'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark s
4  <0> pushmark s
5  <#> gv[*hash] s
6  <1> rv2hv[t4] lK/1
7  <0> pushmark s
8  <#> gv[*_] s
9  <1> rv2av[t2] lKRM*/1
a  <2> aassign[t5] lKS/COMMON
b  <@> anonlist sK*/1
c  <1> rv2av[t10] sKR/1
d  <$> const[IV 1] s
e  <#> gv[*_] s
f  <1> rv2av[t7] sK/1
g  <1> rand[t8] sK/1
h  <2> bit_or[t9] sK
i  <2> aelem vK/2
j  <@> leave[1 ref] vKP/REFC
-e syntax OK
$perl-MO=简明,-exec-e'[@\=%hash]->[1|rand@_]'
1进入
2下一状态(主1-e:1)v:{
3个pushmark s
4个pushmark s
5 gv[*散列]s
6 rv2hv[t4]lK/1
7个pushmark s
8 gv[*.]s
9 rv2av[t2]lKRM*/1
AAS标志[t5]lKS/普通
b单列sK*/1
c rv2av[t10]sKR/1
d常数[IV 1]s
e gv[*Us]
f rv2av[t7]sK/1
g兰特[t8]sK/1
h位_或[t9]sK
i aelem vK/2
j离开[1参考]vKP/REFC
-e语法正常

如果每次运行都需要一个不同的序列,那么首先需要对其进行种子设定,我认为是perl中的srand指令。为什么我需要
srand
it?我每次都要生成一个随机序列,而问题中概述的脚本总是生成相同的第一个值(119)。我想知道为什么在多次调用脚本时,第一个值总是相同的。除非您使用低于5.004的perl版本,否则您不需要使用
srand
。请参阅:
自动调用srand,除非srand已被调用。
@TLP:感谢您的澄清。@Zaid这里有一个非常奇怪的小问题。我是also仔细研究了一下这个随机散列值解决方案,但我觉得我不喜欢它,因为在那里有一段时间使用了
@
@Zaid,我认为你已经在它上戳了一个洞,因为你删除了你的评论和投票。=p这就是解决方案。调用
rand()
不带参数将返回0到1之间的值。将其与按位or组合将保证返回1,这对应于
(值%hash)[0]
。这也解释了为什么其他解决方案不会出现相同的症状。我认为存在漏洞,因为我预期的是
$hash{a}
作为
1 | rand()的结果返回
,直到我记起散列不能保持顺序:)@Zaid我实际上很惊讶地看到我得到了与您相同的第一个值,119。我不知道散列是如何存储或检索的,但它似乎是一致的。尽管这确实提出了一个问题,为什么有人会理智地想在子例程之外设置
@
。请密码
O::简明
output@Zaid,比较
rand
gv[*hash]
+
rv2hv
的相对位置(获取hash)