简体   繁体   English

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

[英]What decides the order of keys when I print a Perl hash?

activePerl 5.8 based 基于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];

Output as this 这样输出

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>

What decided the elements print order in my sample code? 是什么决定了示例代码中元素的打印顺序?

Any rule to follow when print a mixed(strings, numbers) hash in Perl? 在Perl中打印混合(字符串,数字)哈希时要遵循的任何规则? Thank you. 谢谢。

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

[Updated] [更新]

With you guys help, i updated the code as below. 在你们的帮助下,我更新了以下代码。

#!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};
}

output 输出

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

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

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

Finially, after called keys and sort functions. 最后,在调用keyssort函数之后。 The hash keys print followed the rule below 按以下规则打印哈希键

2.5hellobar12.4bettybyefoo35wilma1.72e+030

Elements of a hash are printed out in their internal order, which can not be relied upon and will change as elements are added and removed. 哈希的元素以其内部顺序打印出来,无法依赖,并且会随着元素的添加和删除而发生变化。 If you need all of the elements of a hash in some sort of order, sort the keys, and use that list to index the hash. 如果您需要某种顺序的哈希值的所有元素,请对键进行排序,然后使用该列表为哈希值编制索引。

If you are looking for a structure that holds its elements in order, either use an array, or use one of the ordered hash's on CPAN. 如果要查找按顺序保留其元素的结构,请使用数组或在CPAN上使用有序哈希之一。

the only ordering you can rely upon from a list context hash expansion is that key => value pairs will be together. 您可以从列表上下文哈希扩展中依赖的唯一顺序是键=>值对将在一起。

From perldoc -f keys : perldoc -f键

The keys of a hash are returned in an apparently random order. 哈希键显然是随机顺序返回的。 The actual random order is subject to change in future versions of Perl, but it is guaranteed to be the same order as either the values or each function produces (given that the hash has not been modified). 实际的随机顺序在Perl的未来版本中可能会发生变化,但是可以保证与值或每个函数产生的顺序相同(假定哈希值未修改)。 Since Perl 5.8.1 the ordering is different even between different runs of Perl for security reasons (see Algorithmic Complexity Attacks in perlsec ). 从Perl 5.8.1开始,出于安全原因,即使在不同的Perl运行之间,顺序也有所不同(请参阅perlsec中的算法复杂性攻击 )。

... ...

Perl has never guaranteed any ordering of the hash keys, and the ordering has already changed several times during the lifetime of Perl 5. Also, the ordering of hash keys has always been, and continues to be, affected by the insertion order. Perl从未保证哈希键的任何顺序,并且在Perl 5的生命周期中,该顺序已经改变了几次。而且,哈希键的顺序始终受插入顺序的影响,并将继续受到其影响。

Also note that while the order of the hash elements might be randomised, this "pseudoordering" should not be used for applications like shuffling a list randomly (use List::Util::shuffle() for that, see List::Util , a standard core module since Perl 5.8.0; or the CPAN module Algorithm::Numerical::Shuffle ), or for generating permutations (use eg the CPAN modules Algorithm::Permute or Algorithm::FastPermute ), or for any cryptographic applications. 还要注意,尽管哈希元素的顺序可能是随机的,但这种“伪排序”不应用于诸如随机排序列表之类的应用(为此,请使用List :: Util :: shuffle(),请参见List :: Util ,从Perl 5.8.0开始的标准核心模块;或CPAN模块Algorithm :: Numerical :: Shuffle ),或用于生成置换(例如使用CPAN模块Algorithm :: PermuteAlgorithm :: FastPermute ),或用于任何加密应用程序。


Note: since you are evaluating a hash in list context, you are at least guaranteed that each key is followed by its corresponding value; 注意:由于您要在列表上下文中评估哈希, 因此至少可以确保每个键后面都带有对应的值; eg you will never see an output of a 4 b 3 c 2 d 1 . 例如,您将永远不会看到a 4 b 3 c 2 d 1

I went over your code and made some notes that I think you will find helpful. 我仔细阅读了您的代码,并做了一些说明,认为对您有所帮助。

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";
}

Hashes provide unordered, access to data by a string key. 哈希通过字符串键提供无序访问数据的功能。

Arrays provide access to ordered data. 数组提供对有序数据的访问。 Random access is available by using a numerical index. 通过使用数字索引可以进行随机访问。

If you need to preserve the order of a group of values, use an array. 如果需要保留一组值的顺序,请使用数组。 If you need to look up members of the group by an associated name, use a hash. 如果需要通过关联的名称查找组的成员,请使用哈希。

If you need to do both, you can use both structures together: 如果您需要同时执行这两种操作,则可以同时使用这两种结构:

# 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";
}

Looking at your code samples, I see a couple of things you might want to work on. 在查看您的代码示例时,我看到了一些您可能需要处理的事情。

  • how looping structures like for and while can be used to reduce repeated code. forwhile类的循环结构如何用于减少重复代码。
  • how to use variable interpolation 如何使用变量插值

BTW, I am glad to see you working on basics and improving your code quality. 顺便说一句,很高兴看到您在基础方面进行工作并提高代码质量。 This investment of time will pay off. 这种时间上的投资将得到回报。 Keep up the good work. 保持良好的工作。

The elements are (almost certainly) printed out in the order they appear (internally) in the hash table itself -- ie based on the hash values of their keys. 元素(几乎可以肯定)是按照它们在哈希表本身中(内部)出现的顺序打印出来的,即基于其键的哈希值。

The general rule to follow is to use something other than a hash table if you care much about the order. 遵循的一般规则是,如果您非常关注顺序,则可以使用哈希表以外的其他方法。

Hashes are not (necessarily) retrieved in a sorted manner. 哈希不能(有必要)以排序的方式检索。 If you want them sorted, you have to do it yourself: 如果要对它们进行排序,则必须自己进行:

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";
}

You retrieve all the keys from a hash by using keys and you then sort them using sort . 通过使用键从哈希中检索所有keys ,然后使用sort对其进行sort Yeah, I know, that crazy Larry Wall guy, who would've ever thought of calling them that? 是的,我知道,那个疯狂的拉里·沃尔(Larry Wall)家伙,曾经想过要称呼他们吗? :-) :-)

This outputs: 输出:

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

For most practical purposes, the order in which a hash table (not just Perl hash variables, but hash tables in general) can be considered random. 对于大多数实际目的,可以将哈希表(不仅是Perl哈希变量,而且通常是哈希表)的顺序视为随机的。

In reality, depending on the hashing implementation, the order may actually be deterministic. 实际上,根据哈希实现方式,顺序实际上可能是确定性的。 (ie, If you run the program multiple times putting the same items into the hash table in the same order each time, they'll be stored in the same order each time.) I know that Perl hashes used to have this characteristic, but I'm not sure about current versions. (即,如果您多次运行该程序,并且每次都以相同的顺序将相同的项放入哈希表中,那么它们每次将以相同的顺序进行存储。)我知道Perl哈希曾经具有这种特性,但是我不确定当前版本。 In any case, hash key order is not a reliable source of randomness to use in cases where randomness is desirable. 无论如何,在需要随机性的情况下,哈希键顺序不是可靠的随机性来源。

Short version, then: 短版,然后:

Don't use a hash if you care about the order (or lack of order). 如果您关心顺序(或缺少顺序),请不要使用哈希。 If you want a fixed order, it will be effectively random and if you want a random order, it will be effectively fixed. 如果您想要一个固定的订单,那么它实际上是随机的;如果您想要一个随机的订单,那么它将会被有效地固定。

A hash defines no ordering properties. 哈希没有定义任何排序属性。 The order in which things come out will be unpredictable. 事物出现的顺序将是不可预测的。

And if you are crazy and have no duplicate values in your hash, and you need the values sorted, you can call reverse on it. 而且,如果您发疯了,并且哈希中没有重复的值,并且需要对值进行排序,则可以对其调用反向。

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

print $_ for sort keys %reverse_hash;

Caveat is the unique values part, duplicates will be overwritten and only one value will get in. 注意是唯一值部分,重复项将被覆盖,只有一个值会进入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM