Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Sorting a hash of hashes

by mrc (Sexton)
on May 15, 2012 at 04:57 UTC ( #970560=perlquestion: print w/ replies, xml ) Need Help??
mrc has asked for the wisdom of the Perl Monks concerning the following question:

I have this HoH
my %HoH = ( SUB1 => { Test1 => { value1 => "2300", value2 => "0.01", }, Test2 => { value1 => "5000", value2 => "0.34", }, Test3 => { value1 => "3000", value2 => "0.10", }, Test4 => { value1 => "7000", value2 => "0.33", }, }, SUB2 => { Test1 => { value1 => "2800", value2 => "0.05", }, Test2 => { value1 => "5500", value2 => "0.34", }, }, SUB3 => { Test1 => { value1 => "2700", value2 => "0.25", }, Test2 => { value1 => "5800", value2 => "0.45", }, }, );
Using "Test1" I want to sort it by "value1" and display something like:
for "Test1" SUB2 has value1=2800 SUB1 has value1=2300 OTHERSUB value1=2000 etc.
I don't know how to sort so deep in a hash of hashes or even deeper. Can someone please advice?

Comment on Sorting a hash of hashes
Select or Download Code
Replies are listed 'Best First'.
Re: Sorting a hash of hashes
by NetWallah (Abbot) on May 15, 2012 at 05:56 UTC
    Considerably more compile-able than Utilitarian's code :
    use strict; use warnings; my %HoH = ( SUB1 => { Test1 => { value1 => "2300", value2 => "0.01", }, Test2 => { value1 => "5000", value2 => "0.34", }, }, SUB2 => { Test1 => { value1 => "2800", value2 => "0.05", }, }, ); my %hoa; for my $I (sort keys %HoH){ for my $J (sort keys %{ $HoH{$I} }) { for my $K (sort keys %{ $HoH{$I}{$J} } ){ push @{$hoa{$J}}, [$I,$K, $HoH{$I}{$J}{$K}]; } } } for my $k (sort keys %hoa){ my $entry=$hoa{$k}; print "For $k\n"; for my $item(sort {$a->[1] cmp $b->[1] } @$entry){ print " $item->[0] has $item->[1]=$item->[2]\n" } } __OUTPUT__ For Test1 SUB1 has value1=2300 SUB2 has value1=2800 SUB1 has value2=0.01 SUB2 has value2=0.05 For Test2 SUB1 has value1=5000 SUB1 has value2=0.34
    The code is not the prettiest, - but then, neither is your data structure.

                 I hope life isn't a big joke, because I don't get it.
                       -SNL

      Thanks all! NetWallah, your example seems exactly what I'm looking for. Time to study it and learn some new things about sorting hashes :) Please tell me how to only display the biggest value. Output example:
      __OUTPUT__ For Test1 SUB2 has value1=2800 SUB2 has value2=0.05 For Test2 SUB1 has value1=5000 SUB1 has value2=0.34
        Ok - here you go (Improved names of variables), and did "max" as requested:
        my %rehash; for my $SUBNAME (sort keys %HoH){ for my $testname (sort keys %{ $HoH{$SUBNAME} }) { for my $value_name (sort keys %{ $HoH{$SUBNAME}{$testname} } ){ my $val = $HoH{$SUBNAME}{$testname}{$value_name}; if (exists $rehash{$testname}{$value_name} and $rehash{$testname}{$value_name}[1] > $val){ # Do not update - greater value exists }else{ $rehash{$testname}{$value_name} = [$SUBNAME, $val]; } } } } for my $testname (sort keys %rehash){ print "For $testname:\n"; for my $value_name(sort keys %{ $rehash{$testname} }){ print " $rehash{$testname}{$value_name}[0] has $value_name\=$re +hash{$testname}{$value_name}[1]\n"; } }

                     I hope life isn't a big joke, because I don't get it.
                           -SNL

Re: Sorting a hash of hashes
by Utilitarian (Vicar) on May 15, 2012 at 05:05 UTC
    The sort function takes an optional customised sort routine wherin you compare aspects of $a and $b. perldoc -f sort.
    my %HoH = ( SUB1 => { Test1 => { value1 => "2300", value2 => "0.01", }, Test2 => { value1 => "5000", value1 => "0.34", }, }, SUB2 => { Test1 => { value1 => "2800", value2 => "0.05", }, }, ); for my $sub_key (sort {$HoH{$a}{Test1}{value1} <=> $HoH{$b}{Test1}{val +ue1} }keys %HoH){ print "$HoH{$sub_key}{Test1}{value1}\n"; }
    EDIT: Corrected inline sort routine, original post made pre-coffee and shower :)
    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: Sorting a hash of hashes
by diddy_perl (Novice) on May 15, 2012 at 08:42 UTC

    Try this

    ## Fort test1 ## sort in descending order by value1, select first @values1 = map { $_, $HoH{$_}{'Test1'}{'value1'} } sort { $HoH{$b}{'Test1'}{'value1'} <=> $HoH{$a}{'Test1'}{'value1'} + } keys %HoH; ## sort in descending order by value2, select first @values2 = map { $_, $HoH{$_}{'Test1'}{'value2'} } sort { $HoH{$b}{'Test1'}{'value2'} <=> $HoH{$a}{'Test1'}{'value2'} + } keys %HoH; print "Fort Test1\n"; print " ", $values1[0], " has value1=", $values1[1], "\n"; print " ", $values2[0], " has value2=", $values2[1], "\n"; ## For test2 ## sort in descending order by value1, select first @values1 = map { $_, $HoH{$_}{'Test2'}{'value1'} } sort { $HoH{$b}{'Test2'}{'value1'} <=> $HoH{$a}{'Test2'}{'value1'} + } keys %HoH; ## sort in descending order by value2, select first @values2 = map { $_, $HoH{$_}{'Test2'}{'value2'} } sort { $HoH{$b}{'Test2'}{'value2'} <=> $HoH{$a}{'Test2'}{'value2'} + } keys %HoH; print "Fort Test2\n"; print " ", $values1[0], " has value1=", $values1[1], "\n"; print " ", $values2[0], " has value2=", $values2[1], "\n";

    Enjoy!

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://970560]
Approved by Eliya
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (19)
As of 2015-07-29 13:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (263 votes), past polls