我想使用相同的键构建多个哈希,并且在打印时键要具有相同的顺序。因此,在下面的示例中,$hash1
和$hash2
的键应始终具有相同的顺序,但在创建哈希时不应该保留该顺序。
use Data::Dumper;
my $hash1 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
my $hash2 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
print Dumper $hash1, $hash2;
但输出如下:
$VAR1 = {
'key1' => 1,
'keyc' => 2,
'keyb' => 4,
'keya' => 3
};
$VAR2 = {
'keyb' => 4,
'keya' => 3,
'keyc' => 2,
'key1' => 1
};
即哈希具有不同且意外的顺序。我的perl有什么问题?
我的perl版本是:
This is perl 5, version 18, subversion 2 (v5.18.2) built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)
注意:我知道perl哈希的键是未排序的顺序。我希望他们有相同的订单,但不应该有排序的订单。如果我再次运行代码,我希望能得到相同的打印输出。
根据答案的建议,我设置了两个环境变量:
PERL_HASH_SEED=0x00 PERL_PERTURB_KEYS=0
然后,当我重复运行代码时,我可以获得相同的输出。
答案 0 :(得分:12)
当打印哈希时,有几个不同的顺序概念是相关的:“插入顺序”,“排序顺序”和“随机”。有关可以控制此行为的方法以及默认使用散列随机化的原因的讨论,请参阅ENVIRONMENT section of the perlrun
文档。
在perl中至少十年的哈希值并没有保证关键顺序。最近,散列随机化已经成为一般安全“强化”努力的一部分。哈希有很好的理由随机化。有关详细信息,请参阅perlsec
discussion of algorithmic complexity attacks。您将在Perl安全文档中注意到perl-5.18
中添加了进一步的增强功能 - 如果您看到与先前版本相比的不同行为,则可能是由于这些最近的更改。
除了以确定的方式明确sorting your hash keys之外,您还可以采用其他方法来排序哈希:Hash::Ordered
就是一个例子。 Hash::Ordered
文档很好地讨论了许多其他模块的优缺点。
虽然哈希是按键值对排列的标量的“无序篮子”;数组是标量 [ 1 ] 的“有序序列”。 “slice”是同时访问“列表,数组或散列的几个元素”的方式。切片使用@
sigil,因为操作返回多个值的列表 - 并且@
我们得到“有序序列”。结果是在散列上强加一种“顺序”的一种方法是使用切片来访问它:
# We want alphabetical disorder ...
my %hashed = ( 1 => "z", 2 => "x", 3 => "y" );
for my $key ( keys %hashed ) { print $hashed{$key} } ;
__END__
zyx
我们希望“zxy
”不是“zyx
”。要在这个哈希上强加我们的任意版本的顺序,我们首先需要认识到这里的罪魁祸首是keys %hashed
,它以随机顺序返回密钥。解决方案是使用ccurse的sort
个键,在这个人为的例子中,我们将它们存储在@sort_order
中并用它来“切割”我们想要的哈希值,我们想要的方式:
my @sort_order = sort keys %hashed ;
print @hashed{@sort_order} ;
__END__
zxy
多田!!当您想要在散列中存储键和值但以有序方式访问该数据时,切片会很有用。当你想要切片哈希时,请记住“@
”;正如perldata
所说的那样:“你在哈希切片上使用'@'
... ... [因为]你要回来......一个列表”。列表是有序的。
[ 1 ] 哈希的定义为“无序篮子”,数组为“有序序列”,来自迈克弗里德曼(FRIEDO)关于{{3}的优秀文章}。
进一步参考
perlfaq
-q How can I always keep my hash sorted?,它完整地涵盖了最近的Perl开发和散列随机化问题。答案 1 :(得分:4)
你的perl没有错,散列是未分类的。
如果你想按键排序,你需要做类似的事情:
foreach my $key (sort keys %hash1) {
print $key, $hash1{$key};
}
和hash2一样......
答案 2 :(得分:3)
-G。 Cito的回答是正确的。但是,如果您想要Data :: Dumper的排序输出,您可以这样做:
use Data::Dumper;
my $hash1 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
my $hash2 = {
keyc => 2,
key1 => 1,
keya => 3,
keyb => 4,
};
my $dumper = Data::Dumper->new([$hash1, $hash2]);
$dumper->Sortkeys(1);
print $dumper->Dump;