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

Hello, in which way can I sort a multidimensional hash by a specific column, i.e.:
$hash->{"AAA"}->{"KEY1"} = "VALUE1"; $hash->{"AAA"}->{"KEY2"} = "VALUE2"; $hash->{"AAA"}->{"KEY3"} = "VALUE3";
How would I sort by KEY2??? Thanx a lot ;-)

Replies are listed 'Best First'.
Re: Sorting a multidimensional hash by column
by moritz (Cardinal) on Jun 25, 2010 at 09:46 UTC
    Please see that "how do I sort..." entries in perlfaq4.

    And remember that you have to store the result in an array and not in a hash, because hashes don't preserve order.

Re: Sorting a multidimensional hash by column
by cdarke (Prior) on Jun 25, 2010 at 10:56 UTC
    KEY2 is a single key with a single value, so you can't sort that. Maybe you mean "by the second key"? But you don't say if you want to sort the keys or the values. OK, since you said KEY2 then I'll guess you want to sort the keys.

    I added some data items to your hash, I don't know your data format, but I hope you get the idea. You might try this:
    use strict; use warnings; my $hash; $hash->{"AAA"}->{"KEY1"} = "VALUE1"; $hash->{"AAA"}->{"KEY2"} = "VALUE2"; $hash->{"AAA"}->{"KEY3"} = "VALUE3"; $hash->{"AAA"}->{"KEY9"} = "VALUE3"; $hash->{"AAA"}->{"KEY10"} = "VALUE3"; $hash->{"AAA"}->{"KEY123"} = "VALUE3"; $hash->{"AAA"}->{"KAY1"} = "VALUE1"; $hash->{"AAA"}->{"KAY2"} = "VALUE2"; $hash->{"AAA"}->{"KAY3"} = "VALUE3"; my @result = sort keys %{$hash->{"AAA"}}; print "@result\n";
    But that just gives:
    KAY1 KAY2 KAY3 KEY1 KEY10 KEY123 KEY2 KEY3 KEY9
    because the default sort is textual. We want a numeric sort on the second part of the key (I'm guessing here on your data format) so we need a bit more work:
    sub keycmp { $a =~ /^(\D*)(\d*)$/; my $a_txt = $1; my $a_num = $2; $b =~ /^(\D*)(\d*)$/; my $b_txt = $1; my $b_num = $2; if ($a_txt eq $b_txt) { return $a_num <=> $b_num } else { return $a_txt cmp $b_txt } } @result = sort keycmp keys %{$hash->{"AAA"}}; print "@result\n";
    Gives:
    KAY1 KAY2 KAY3 KEY1 KEY2 KEY3 KEY9 KEY10 KEY123
Re: Sorting a multidimensional hash by column
by dcronin135 (Acolyte) on Jul 08, 2015 at 00:22 UTC

    Another variation for sorting a multi dimensional hash.

    #!/usr/bin/perl # Sorting a multi dimensional hash example. my %user, $uname, $i, $score; my @List = qw(Charlie Madi Becky Paul); foreach $uname (@List) { $user{$uname}{'user'}=$uname; $user{$uname}{'score'}=int(rand(800))+100; } # unsorted print "- unsorted -\n\n"; foreach $i (keys %user) { print "$user{$i}{'user'}\t$user{$i}{'score'}\n"; } # Sort ascending on score dimension print "\n\n - Sort on score dimension ascending -\n\n"; foreach $i ( sort { $user{$a}{'score'} <=> $user{$b}{'score'} } keys % +user) { print "$user{$i}{'user'}\t$user{$i}{'score'}\n"; } # Sort descending on score dimension print "\n\n - Sort on score dimension descending -\n\n"; foreach $i ( sort { $user{$b}{'score'} <=> $user{$a}{'score'} } keys % +user) { print "$user{$i}{'user'}\t$user{$i}{'score'}\n"; } exit 0;


    Sample output
    # perl hsort2d.pl
    - unsorted -

    Paul      684
    Becky   162
    Charlie  694
    Madi     805

    - Sort on score dimension ascending -

    Becky   162
    Paul      684
    Charlie  694
    Madi     805

    - Sort on score dimension descending -

    Madi     805
    Charlie  694
    Paul      684
    Becky   162

    #

Re: Sorting a multidimensional hash by column
by Utilitarian (Vicar) on Jun 27, 2010 at 09:02 UTC
    Hi piccard, I am assuming that you need to sort hashes of AAA, BBB...
    The following works if my assumption is correct.
    #!/usr/bin/perl use strict; use warnings; my($hash); $hash->{"AAA"}->{"KEY1"} = "VALUE1"; $hash->{"AAA"}->{"KEY2"} = "VALUE2"; $hash->{"AAA"}->{"KEY3"} = "VALUE3"; $hash->{"BBB"}->{"KEY1"} = "VALUEA"; $hash->{"BBB"}->{"KEY2"} = "VALUEB"; $hash->{"BBB"}->{"KEY3"} = "VALUEC"; for my $set (sort {$hash->{$a}->{"KEY2"} cmp $hash->{$b}->{"KEY2"}} (k +eys %{$hash})){ print "$set:\n"; for my $key (sort(keys %{$hash->{$set}})){ print "\t$key: $hash->{$set}->{$key}\n"; } }
    The above returns
    AAA: KEY1: VALUE1 KEY2: VALUE2 KEY3: VALUE3 BBB: KEY1: VALUEA KEY2: VALUEB KEY3: VALUEC
    sort takes an optional code block which uses the package variables $a and $b for comparison of the members of the list.

    Hope that helps

    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."