What decides the order of keys when I print a Perl

2019-01-12 07:25发布

activePerl 5.8 based

#!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? 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. The hash keys print followed the rule below

2.5hellobar12.4bettybyefoo35wilma1.72e+030

标签: perl hash
8条回答
甜甜的少女心
2楼-- · 2019-01-12 07:43

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.
  • 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.

查看更多
闹够了就滚
3楼-- · 2019-01-12 07:51

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.

In reality, depending on the hashing implementation, the order may actually be deterministic. (i.e., 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. 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.

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-01-12 07:52

The elements are (almost certainly) printed out in the order they appear (internally) in the hash table itself -- i.e. 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.

查看更多
我只想做你的唯一
5楼-- · 2019-01-12 07:55

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.

the only ordering you can rely upon from a list context hash expansion is that key => value pairs will be together.

查看更多
狗以群分
6楼-- · 2019-01-12 07:56

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.

查看更多
趁早两清
7楼-- · 2019-01-12 07:57

A hash defines no ordering properties. The order in which things come out will be unpredictable.

查看更多
登录 后发表回答