Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Sorting a hash of hashes

by mrc (Sexton)
on May 15, 2012 at 04:57 UTC ( [id://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?

Replies are listed 'Best First'.
Re: Sorting a hash of hashes
by NetWallah (Canon) 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
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-04-19 14:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found