Plankton has asked for the wisdom of the Perl Monks concerning the following question:

Friends

Why does this ...

#!/usr/bin/perl my %HoTypes = ( 'PythonQuestions' => [ '[PythonQuestions|Python Questions]', 318, +3, 10 ], 'OffTopics' => [ '[OffTopics|Off Topic Post]', 500, +3, 10 ], 'notes' => [ 'Notes', 283, +3, 20 ] ); for my $T ( keys %HoTypes ) { my $nodeStr = $HoTypes{$T}[0]; print "$T -> $nodeStr\n"; }
... outputs this ...
PythonQuestions -> [PythonQuestions|Python Questions] notes -> Notes OffTopics -> [OffTopics|Off Topic Post]
... and not this ...
PythonQuestions -> [PythonQuestions|Python Questions] OffTopics -> [OffTopics|Off Topic Post] notes -> Notes

Plankton: 1% Evil, 99% Hot Gas.Snakehandlers!

Replies are listed 'Best First'.
Re: I don't understand why keys %hash does this ...
by tachyon (Chancellor) on Oct 05, 2004 at 06:04 UTC

    You seem to expect to get the keys out of the hash in the same order you declared them. You won't. Hash keys are unsorted. You need to apply a sort if you need them in a specific order, or perhaps use an array of arrays data structure which would preserve the order.

    cheers

    tachyon

Re: I don't understand why keys %hash does this ...
by FoxtrotUniform (Prior) on Oct 05, 2004 at 06:04 UTC

    Hashes are not sorted. They're designed for direct data lookup, not ordering. If order is important to you, use an array (or sort the keys before you use them).

    --
    F o x t r o t U n i f o r m
    Found a typo in this node? /msg me
    % man 3 strfry

Re: I don't understand why keys %hash does this ...
by si_lence (Deacon) on Oct 05, 2004 at 06:13 UTC
    Hi there,
    If you want to keep using a hash you can use Tie::IxHash
    It gives you back the keys in the order you inserted them.
    hth
    si_lence
Re: I don't understand why keys %hash does this ...
by Roger (Parson) on Oct 05, 2004 at 06:20 UTC
    The monks have pointed out that hash order is not preserved. I just want to point out that one method I often use to preserve the order of the input hash is to use an intermediate array:

    #!/usr/bin/perl use strict; use Data::Dumper; my %HoTypes = my @HoTypes = ( 'PythonQuestions' => [ '[PythonQuestions|Python Questions]', 318, +3, 10 ], 'OffTopics' => [ '[OffTopics|Off Topic Post]', 500, +3, 10 ], 'notes' => [ 'Notes', 283, +3, 20 ] ); # retrieve the keys in the original order @HoTypes = @HoTypes[map { $_ % 2 ? () : $_ } 0..$#HoTypes]; # and use the keys recorded in the array for my $T ( @HoTypes ) { my $nodeStr = $HoTypes{$T}[0]; print "$T -> $nodeStr\n"; }

Re: I don't understand why keys %hash does this ...
by grinder (Bishop) on Oct 05, 2004 at 08:02 UTC

    In a similar vein to Roger's post, if you want to maintain order, then use a list. You could use a list of hashes of two keys. One key points to the label/name, the other to the data you are looking after:

    my @type = ( { name => 'PythonQuestions', data => [ '[PythonQuestions|Python Questions]', 318, 3, 10 ], }, { name => 'OffTopics', data => [ '[OffTopics|Off Topic Post]', 500, 3, 10 ], }, { name => 'notes', data => [ 'Notes', 283, 3, 20 ], }, ); for my $t( @type ) { print "$t->{name} -> $t->{data}[0]\n"; }

    The main question is whether or not you need to use the hash for lookups. E.g., if you never need to find out what $HoTypes{$thing} points to, for some value of $thing, if all you ever do is iterate over all the keys in a loop, you can get away with a list.

    Sometimes a hash is more trouble than it's worth.

    - another intruder with the mooring of the heat of the Perl

Re: I don't understand why keys %hash does this ...
by cLive ;-) (Prior) on Oct 05, 2004 at 08:06 UTC
    A nice quick way to do what you want is to add an "index" field at the end of the arrayref:
    my %HoTypes = ( 'PythonQuestions' => [ '[PythonQuestions|Python Questions]', 318, +3, 10, 0 ], 'OffTopics' => [ '[OffTopics|Off Topic Post]', 500, +3, 10, 1 ], 'notes' => [ 'Notes', 283, +3, 20, 2 ] );
    and then sort based on index:
    for my $T ( sort { $HoTypes{$a}[-1] <=> $HoTypes{$b}[-1] } keys %HoTyp +es ) { my $nodeStr = $HoTypes{$T}[0]; print "$T -> $nodeStr\n"; }
    Untested, but I think that would do the trick.

    cLive ;-)

Re: I don't understand why keys %hash does this ...
by Anonymous Monk on Oct 05, 2004 at 09:03 UTC
    No offence intended, but how could someone who is a pontiff AND a member of pmdev not know such a basic fact about hashes (and moreover not know where to find the answer) ?!
    A reply falls below the community's threshold of quality. You may see it by logging in.