我打印Perl哈希时决定键的顺序是什么?

时间:2010-01-06 06:42:35

标签: perl hash

基于activePerl 5.8

#!C:\Perl\bin\perl.exe
use strict;
use warnings;

# declare a new hash
my %some_hash;

%some_hash = ("foo", 35, "bar", 12.4, 2.5, "hello",
      "wilma", 1.72e30, "betty", "bye\n");

my @any_array;
@any_array = %some_hash;

print %some_hash;
print "\n";
print @any_array;
print "\n";
print $any_array[0];
print "\n";
print $any_array[1];
print "\n";
print $any_array[2];
print "\n";
print $any_array[3];
print "\n";
print $any_array[4];
print "\n";
print $any_array[5];
print "\n";
print $any_array[6];
print "\n";
print $any_array[7];
print "\n";
print $any_array[8];
print "\n";
print $any_array[9];

以此输出

D:\learning\perl>test.pl
bettybye
bar12.4wilma1.72e+030foo352.5hello
bettybye
bar12.4wilma1.72e+030foo352.5hello
betty
bye

bar
12.4
wilma
1.72e+030
foo
35
2.5
hello
D:\learning\perl>

我的示例代码中的元素打印顺序是什么?

在Perl中打印混合(字符串,数字)哈希时要遵循的任何规则?谢谢。

bar12.4wilma1.72e+030foo352.5hello

[更新]

在你们的帮助下,我更新了以下代码。

#!C:\Perl\bin\perl.exe
use strict;
use warnings;

# declare a new hash
my %some_hash;

%some_hash = ("foo", 35, "bar", 12.4, 2.5, "hello",
      "wilma", 1.72e30, "betty", "bye");

my @any_array;
@any_array = %some_hash;

print %some_hash;
print "\n";
print "\n";
print @any_array;
print "\n";
print "\n";

my @keys;
@keys = keys %some_hash;
for my $k (sort @keys)
{
    print $k, $some_hash{$k};
}

输出

D:\learning\perl>test.pl
bettybyebar12.4wilma1.72e+030foo352.5hello

bettybyebar12.4wilma1.72e+030foo352.5hello

2.5hellobar12.4bettybyefoo35wilma1.72e+030
D:\learning\perl>

最终,在调用keyssort函数后。哈希键打印遵循以下规则

2.5hellobar12.4bettybyefoo35wilma1.72e+030

8 个答案:

答案 0 :(得分:22)

哈希的元素按其内部顺序打印出来,不能依赖它们,并且会随着元素的添加和删除而改变。如果您需要某种顺序的哈希的所有元素,请对键进行排序,并使用该列表来索引哈希。

如果您正在寻找一个按顺序保存其元素的结构,可以使用数组,也可以在CPAN上使用其中一个有序哈希值。

您可以依赖列表上下文哈希扩展的唯一顺序是key =>价值对将在一起。

答案 1 :(得分:9)

来自perldoc -f keys

  

散列的键以明显随机的顺序返回。实际的随机顺序在未来的Perl版本中可能会发生变化,但保证与值或每个函数产生的顺序相同(假设散列未被修改)。从Perl 5.8.1开始,出于安全原因,即使在不同的Perl运行之间,顺序也不同(参见Algorithmic Complexity Attacks in perlsec)。

...

  

Perl从未保证任何散列键的排序,并且在Perl 5的生命周期中排序已经多次改变。此外,散列键的排序一直并且继续受插入顺序的影响

     

另请注意,虽然哈希元素的顺序可能是随机的,但这种“伪目标”不应该用于随机填充列表的应用程序(请使用List :: Util :: shuffle(),请参阅{{3自Perl 5.8.0以来的标准核心模块;或CPAN模块List::Util),或用于生成排列(使用例如CPAN模块Algorithm::Numerical::ShuffleAlgorithm::Permute),或任何加密应用程序。


注意:由于您正在评估列表上下文中的哈希,因此 至少保证每个键后跟其对应的值;例如你永远不会看到a 4 b 3 c 2 d 1的输出。

答案 2 :(得分:3)

我查看了你的代码并做了一些我认为你会发现有用的笔记。

use strict;
use warnings;

# declare a new hash and initialize it at the same time
my %some_hash = (
    foo   => 35,       # use the fat-comma or '=>' operator, it quotes the left side
    bar   => 12.4,     
    2.5   => "hello",
    wilma => 1.72e30,
    betty => "bye",    # perl ignores trailing commas, 
                       # the final comma makes adding items to the end of the list less bug prone.
);

my @any_array = %some_hash; # Hash is expanded into a list of key/value pairs.

print "$_ => $some_hash{$_}\n" 
    for keys %some_hash;

print "\n\n",              # You can print multiple newlines in one string.
      "@any_array\n\n";    # print takes a list of things to print.

# In print @foo; @foo is expanded into a list of items to print.  
# There is no separator between the members of @foo in the output.

# However print "@foo"; interpolates @foo into a string. 
# It inserts spaces between the members of the arrays.


# This is the block form of 'for'
for my $k (sort keys %some_hash)
{
    # Interpolating the variables into a string makes it easier to read the output.
    print "$k => $some_hash{$k}\n";
}

哈希提供无序的,通过字符串键访问数据。

Arrays提供对有序数据的访问。使用数字索引可以随机访问。

如果需要保留一组值的顺序,请使用数组。如果您需要通过关联名称查找组成员,请使用哈希。

如果您需要同时使用这两种结构:

# Keep an array of sorted hash keys.
my @sorted_items = qw( first second third fourth );

# Store the actual data in the hash.
my %item;
@item{ @sorted_items } = 1..4;  # This is called a hash slice.  
                                # It allows you to access a list of hash elements.
                                # This can be a very powerful way to work with hashes.

# random access
print "third => $item{third}\n";


# When you need to access the data in order, iterate over
# the array of sorted hash keys.  Use the keys to access the
# data in the hash.

# ordered access
for my $name ( @sorted_items ) {
    print "$name => $item{$name}\n";
}

查看代码示例,我看到了一些您可能想要处理的事情。

  • 如何使用forwhile这样的循环结构来减少重复的代码。
  • 如何使用变量插值
顺便说一句,我很高兴看到您致力于基础知识并提高您的代码质量。这种时间投入将得到回报。保持良好的工作。

答案 3 :(得分:2)

元素(几乎可以肯定)按照它们在(在内部)在哈希表本身中出现的顺序打印出来 - 即基于其键的哈希值。

如果您非常关心订单,则遵循的一般规则是使用哈希表以外的其他内容。

答案 4 :(得分:2)

不一定(必然)以排序方式检索哈希值。如果你想要它们排序,你必须自己做:

use strict;
use warnings;

my %hash = ("a" => 1, "b" => 2, "c" => 3, "d" => 4);

for my $i (sort keys %hash) {
    print "$i -> $hash{$i}\n";
}

使用keys从哈希中检索所有密钥,然后使用sort对其进行排序。是的,我知道,那个疯狂的拉里沃尔家伙,曾经想过要把他们称为那个?: - )

输出:

a -> 1
b -> 2
c -> 3
d -> 4

答案 5 :(得分:1)

对于大多数实际用途,哈希表(不仅仅是Perl哈希变量,而是一般的哈希表)的顺序可以被认为是随机的。

实际上,根据哈希实现,订单实际上可能是确定性的。 (也就是说,如果你多次运行程序,每次都以相同的顺序将相同的项目放入哈希表中,那么每次都会以相同的顺序存储它们。)我知道Perl哈希曾经有过这个特性,但是我不确定当前的版本。在任何情况下,散列键顺序不是在需要随机性的情况下使用的可靠随机源。

简短版本,然后:

如果您关心订单(或缺乏订单),请不要使用哈希。如果你想要一个固定的订单,它将是有效的随机,如果你想要一个随机的订单,它将被有效地修复。

答案 6 :(得分:0)

哈希定义没有排序属性。事情发生的顺序是不可预测的。

答案 7 :(得分:0)

如果你疯了并且你的哈希值没有重复值,并且你需要对值进行排序,你可以在它上面调用reverse。

my %hash = ("a" => 1, "b" => 2, "c" => 3, "d" => 4);
my %reverse_hash = reverse %hash;

print $_ for sort keys %reverse_hash;

警告是唯一的值部分,重复将被覆盖,只有一个值进入。