http://qs321.pair.com?node_id=89128


in reply to problem with hash keys

Hashes do not preserve insertion order. In other words, it is simply a fluke that your examples #1 and #2 print out the hash keys in the correct order; they are the exception rather than the rule.

If you just want the keys sorted alphabetically, use

for my $k (sort keys %GRAMMAR) {
But you may run into situations where you really do want to preserve insertion order, and it's not just a matter of sorting alphabetically.

If you want to preserve insertion order and still use a hash, take a look at Tie::IxHash. Or, if you're not wedded to a hash, you could always use an array, and push array refs onto your list of grammars:

push @GRAMMAR, [ $1, $2 ];
And then when iterating:
for my $rec (@GRAMMAR) { print $rec->[0], "\n"; }
BTW, when you do a regex match w/ capturing parens, you really should check whether the regex successfully matches:
next unless /([A-Z]) -> (.*)/; $GRAMMAR{$1} = $2;
That way, if the regex fails--ie. the line you're looking at doesn't match that regex--you'll just skip that line. You don't want to use $1 and $2 if the match was unsuccessful, because there's no telling what they could contain. :)

Replies are listed 'Best First'.
Re: Re: problem with hash keys
by june_bo (Novice) on Jun 17, 2001 at 07:25 UTC
    Thanks for all the good advice.
    I need to keep the order for cosmetic reasons; the user will expect to see the end results (a bunch of sets) in the same order he entered them.
    I have to use hashes because I do (what I think are) wonderful and amazing things with them later in the program.

    Thanks again to everyone.
    -tl

      Then you can additionally store for each hash the order in which its keys are in:
      # ... push @grammar_keys, $1 unless exists $grammar{$1}; $grammar{$1} = $2; # ... print "$k\n" for my $k (@grammar_keys);
      (I've also taken the liberty of using lowercase variable names; you should probably use all-uppercase names only for special global variables).

      Or you can use a module like Tie::IxHash, which implements hashes with ordered keys just like you want.