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

Sort Hash of Hashes by key value

by jgn (Initiate)
on Mar 14, 2011 at 19:04 UTC ( #893112=perlquestion: print w/ replies, xml ) Need Help??
jgn has asked for the wisdom of the Perl Monks concerning the following question:


I am new'ish to Perl and have taken on a project to create some scripts to monitor some Windows Servers.

The piece that is giving me a lot of trouble is sorting my hash of hashes I am generating as I go through a list of machines.

This is my snippet that tacks a hash onto the hash for each machine that meets my criteria, 97% full volume.
if (( $pctused ) > 97 ) { $srvlist{ $srvname } = { pctused => "$pctused", volname => "$volname", volfree => "$volfree" }; }
This all works fine. Each machine that meets this criteria is tacked onto the hash. However I am at a complete loss for how to sort by the value of one of these keys when I generate my report. I have tinkered with the various sort methods I have found in my google search and no joy.

While I'm sure there is a better way to do it than I have here... My question is how can I sort by key value in a hash of hashes and "rebuild" it as a sorted list for say ... sticking it into an HTML table?

Thanks in advance

Comment on Sort Hash of Hashes by key value
Download Code
Replies are listed 'Best First'.
Re: Sort Hash of Hashes by key value
by TomDLux (Vicar) on Mar 14, 2011 at 20:01 UTC

    Seems to me you're going to want the server name in your output, too.

    The trivial way to arrange that is to stick another key-value pair server => 'foobar47' into each set. But wh6y have a top level hash, in the first place? ... unless you're doing things by name basis, elsewhere, just make it a top-level array:

    push @servers, { server => 'foobar47', pctused => $pctused, volname => $volname, volfree => $volfree } if $pctused > $LIMIT;

    You don't need to put variables between quote to have them interpolated, you just want the value. So now you can sort the list based on the pctused.

    my @sorted = sort { $a->{pctused} <=> $b->{pctused} } @servers;

    The other way is to use a Schwartzian Transform. Extract the keys from the original data structure; use that to form pairs where the first element is what you want to sort by, and the second element is the true key. Sort by the first elements. Then extract the true keys, i.e. the server names, sorted by the otehr element.

    It looks kind of scary if you're new to Perl. The key concept is that map takes an array on the right, whose elements are processed one by one in the block which follows the 'map' keyword, where it's known as '$_'

    my @sorted_server_names = map { $_->[1] } sort { $a->[0] <=> $b-><[0] map { [ $srvlist{$_}{pctused}, $_ ] } keys %srvlist

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

Re: Sort Hash of Hashes by key value
by philipbailey (Chaplain) on Mar 14, 2011 at 19:24 UTC

    Something like this should do it:

    use Data::Dumper; print Dumper $_ for sort { $servlist{$a}{volname} cmp $servlist{$b}{vo +lname} } keys %servlist;
Re: Sort Hash of Hashes by key value
by chrestomanci (Priest) on Mar 14, 2011 at 19:24 UTC

    It is fairly easy to do. You can use the values function to get back a list of hash elements. eg

     my @items = values %srvlist

    That will give you a list in a random(ish) order. To sort the list, you can pass the sort function a closure that tell it how to sort. eg

     my @sorted_list = sort { $a->{'pctused'} <=> $b->{'pctused'} values %srvlist

    $a and $b are temporary variables used only within the sort closure, <=> is the spaceship operator which numerically compares numbers. You would use cmp if you where comparing strings.

    Edit: Correct an error pointed out by johngg. Thanks

      I'm puzzled by your recommendation of an "elements" function as that's a new one on me. Did you mean values, perchance?



        Yes I did, thanks.

        I think I was getting confused with another language.

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (7)
As of 2016-02-14 15:22 GMT
Find Nodes?
    Voting Booth?

    How many photographs, souvenirs, artworks, trophies or other decorative objects are displayed in your home?

    Results (470 votes), past polls