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

Hi Monks,

Super Simple, I suppose ...

The piece of code beneath outputs the keys and values of the hash ... How do I sort this hash so that Number will be printed first ?

my %hash = ( EX => 'ArraySite', AM => 'IOPort', PLE => 'AddressGroup', Number => '11', ); for my $key ( keys %hash ) { my $value = $hash{$key}; print "$key => $value\n"; }

Replies are listed 'Best First'.
Re: Hash Order
by jeffa (Bishop) on Nov 17, 2008 at 19:18 UTC

    If you are able to ... then change your data! :)

    my %hash = ( EX => { sort => 30, data => 'ArraySite' }, AM => { sort => 40, data => 'IOPort' }, PLE => { sort => 20, data => 'AddressGroup' }, Number => { sort => 1, data => '11' }, ); for my $key (sort { $hash{$a}->{sort} <=> $hash{$b}->{sort} } keys %ha +sh) { print $key, " => ", $hash{$key}->{data}, "\n"; }

    What happens when 'Number' has to be renamed, or another key is added whose length is longer than 'Number?' I would first try to make the data work for me rather than the other way around, if possible.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Hash Order
by MidLifeXis (Monsignor) on Nov 17, 2008 at 19:08 UTC

    Assume: 'Number' always exists, and the order of the rest of the keys do not matter.

    my %hash = ( EX => 'ArraySite', AM => 'IOPort', PLE => 'AddressGroup', Number => '11', ); for my $key ( 'Number', (grep {$_ ne 'Number'} keys %hash) ) { my $value = $hash{$key}; print "$key => $value\n"; }

    --MidLifeXis

      Combining this with other code from perlfaq4 (maybe just a previous version; see `perldoc -q duplicate`):
      my %seen; for my $key ( 'Number', keys %hash) ) { next if $seen{$key}++; my $value = $hash{$key}; print "$key => $value\n"; }
Re: Hash Order
by ccn (Vicar) on Nov 17, 2008 at 19:01 UTC
    Using knowledge that 'Number' is the key of longest length:
    for my $key ( sort {length($b) <=> length($a)} keys %hash ) { my $value = $hash{$key}; print "$key => $value\n"; }

    or more generalized using auxiliary hash:

    my %order = (Number => 1, EX => 2); for my $key ( sort { ($order{$a}||1000) <=> ($order{$b}||1000)} keys % +hash ) { my $value = $hash{$key}; print "$key => $value\n"; }

    Update: It's funny but your code prints 'Number' first for me without any sort procedure.

Re: Hash Order
by toolic (Bishop) on Nov 17, 2008 at 19:17 UTC
    If you can control how the hash is created, you could enforce a desired ordering using Tie::IxHash:
    use strict; use warnings; use Tie::IxHash; tie my %hash, "Tie::IxHash"; %hash = ( Number => '11', EX => 'ArraySite', AM => 'IOPort', PLE => 'AddressGroup', ); for (keys %hash) { print "$_ => $hash{$_}\n" } __END__ Number => 11 EX => ArraySite AM => IOPort PLE => AddressGroup

    Update: Running a Super Search (?node_id=3989;HIT=hash%20order;re=N) yields (among many other relevant nodes) Best method to order a hash of arrays.

Re: Hash Order
by JavaFan (Canon) on Nov 17, 2008 at 19:12 UTC
    print "Number => $hash{Number}\n"; while (my ($k, $v) = each %hash) { next if $k eq 'Number'; print "$k => $v\n"; }