在Perl中,为什么`values%hash`的顺序与我用于创建%hash的列表中的顺序不同?

时间:2015-06-19 12:49:59

标签: perl

我从哈希中提取数组,我已经打印了数组,但可以看到输出顺序不同。这是为什么?

我的代码:

amqcrsta

3 个答案:

答案 0 :(得分:4)

哈希表没有订单。如果您希望以特定顺序输出值,则可以按顺序迭代键:

for my $person (('John Paul', 'Kumar', 'Lisa')) {
    my $age = $data{ $person };
    ...

或者,使用具有所需键顺序的哈希切片:

@ages = @data{ ('John Paul', 'Kumar', 'Lisa') };

另请参阅常见问题列表中的How can I make my hash remember the order I put elements into it?

您应至少阅读常见问题列表几次。

答案 1 :(得分:2)

除非你使用类似Tie::IxHash的东西看起来像哈希但实际上并不是(这意味着它没有哈希的相同性能特征),你得到的顺序元素将是不可预测的 [1] 。因此,通过一些外部手段(例如sort)控制哈希元素的访问顺序是一种常见做法。

for my $key (sort keys(%hash)) {
   ...
}

哈希是链表的数组。散列函数将密钥转换为一个数字,该数字用作存储值的数组元素(" bucket")的索引。链表处理多个键散列到同一索引的情况(" collision")。

因此元素按索引自然排序,也就是说按键的哈希值。对于不经意的观察者来说,这个顺序似乎是随机的。

但出于安全原因,Perl会对此自然顺序进行更改。

当存储桶开始接收散列的大部分元素时,散列的性能会降低,因为查找会成为链接列表的搜索。恶意行为者可以通过故意提供会触发退化案例的价值来管理系统。

Perl采取措施避免这种情况,并在事故或意图恶化时修复哈希值。我不熟悉所有细节,而且他们在一年中发生了变化。它们涉及随机化散列算法并随机化返回元素的顺序。

这使得订单显得更加随机,

  1. 一个例外:只要您不改变,keysvalueeach返回元素的顺序对于给定的哈希始终是相同的哈希。

    $ perl -E'
       @h{ "a".."i" } = 0..8;
       say map { $h{$_} } keys %h;
       say map { $h{$_} } keys %h;
       say values %h;
    
       $h{j} = 9;
       say map { $h{$_} } keys %h;
       say map { $h{$_} } keys %h;
       say values %h;
    '
    580734216
    580734216
    580734216
    0985216734
    0985216734
    0985216734
    

    可以安全地执行以下操作:

    # Add the elements of %hash1 to %hash2.
    @hash2{ keys(%hash1) } = values(%hash1);
    

答案 2 :(得分:0)

来自perldoc

  

哈希条目以明显随机的顺序返回。实际的随机顺序特定于给定的哈希值;两个哈希值上完全相同的一系列操作可能会导致每个哈希值的顺序不同。任何插入哈希都可以改变顺序,任何删除也是如此,除了可以删除每个或多个键返回的最新密钥而不改变顺序。只要给定的散列未经修改,您可以依赖于键,值和每个重复返回相同的顺序。有关哈希顺序随机化的详细信息,请参阅Algorithmic Complexity Attacks in perlsec