我想使用相同的键构建多个哈希值,并且在打印它们时使键具有相同的顺序。因此,在下面的示例中,
$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
};
i.e 哈希值具有不同且意外的顺序。我的 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
然后当我重复运行代码时可以获得相同的输出。
打印哈希时,有一些相关的不同顺序概念:“插入顺序”、“排序顺序”和“随机”。请参阅 perlrun
至少十年来,perl 中的哈希值并不能保证键的顺序。最近,哈希随机化已成为一般安全“强化”工作的一部分。哈希值被随机化是有充分理由的。有关更多详细信息,请参阅
perlsec
算法复杂性攻击的讨论。您会在 Perl 安全文档中注意到,perl-5.18
中添加了进一步的增强功能 - 如果您看到与以前版本相比不同的行为,可能是由于这些最新的更改所致。
除了以确定性方式明确对哈希键进行排序之外,您还可以采用其他方法来对哈希进行排序:
Hash::Ordered
就是一个例子。 Hash::Ordered
文档对许多其他模块的优缺点进行了很好的讨论。
虽然哈希是按键值对排列的标量的“无序篮子”;数组是标量[1]的“有序序列”。 “slice”是“同时访问列表、数组或散列的多个元素”的方式。切片使用
@
符号,因为该操作返回多个值的列表 - 并且使用 @
我们得到“有序序列”。结果是,对哈希施加某种“顺序”的一种方法是使用切片来访问它:
# 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] 哈希作为“无序篮子”和数组作为“有序序列”的定义来自 Mike Friedman (FRIEDO) 关于 Arrays vs. Lists in Perl 的优秀文章。
更多参考资料
perlfaq
-q 我怎样才能始终保持哈希排序?你的 Perl 没有任何问题,哈希值未排序。
如果你想按键排序,你需要这样做:
foreach my $key (sort keys %hash1) {
print $key, $hash1{$key};
}
对于 hash2 也是同样的事情...
G。西托的回答是正确的。但是,如果您想从 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;