为什么哈希键在打印时有不同的顺序?

时间:2015-05-20 03:58:33

标签: perl sorting data-structures hash perl-data-structures

我想使用相同的键构建多个哈希,并且在打印时键要具有相同的顺序。因此,在下面的示例中,$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

然后,当我重复运行代码时,我可以获得相同的输出。

3 个答案:

答案 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}的优秀文章}。

进一步参考

答案 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;