2015-06-19 93 views
1

我从哈希中提取数组,但我已经打印数组,但可以看到输出的顺序是不同的。为什么是这样?在Perl中,为什么`values%hash`的顺序与我用来创建%hash的列表中的顺序不同?

我的代码:

#!/usr/bin/perl 

%data = ('John Paul' => 45, 'Lisa' => 30, 'Kumar' => 40); 

@ages = values %data; 

print "$ages[0]\n"; 
print "$ages[1]\n"; 
print "$ages[2]\n"; 
+1

@serenesat不,散列没有订单,直到你强加在他们身上的外部的顺序关系。数组有秩序,因为它们的键是定义在其上的自然顺序的整数,而不考虑它们的使用方式。即使如此,数组的自然顺序可能并不是您想要强加给数据结构的顺序,这就是为什么存在“排序”功能的原因。 –

+0

是的。删除我的评论。 – serenesat

回答

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?在FAQ列表中。

您应该阅读FAQ列表至少几次。

0

perldoc

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

2

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

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

散列是链表的阵列。散列函数将该键转换为一个数字,该数字用作存储该值的数组元素(“存储区”)的索引。链表处理多个密钥散列到同一个索引(“碰撞”)的情况。

所以元素自然按索引排序,也就是说通过它们的键的散列。对于偶然的观察者来说,这个命令似乎是随机的。


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

当存储桶开始接收大部分散列元素时,由于查找成为链接列表的搜索,散列表现会降低。恶意行为者可以通过故意提供可触发退化事件的值来对系统进行DOS操作。

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); 
    
相关问题