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

Hi monks,

Can anyone tell me if its possible to use sort to do a "double sort" of hash values?
Heres an example to demo what i want...
#!/usr/bin/perl use strict; use warnings; my %bar = ( # Name => [Age, Pets, Profession] 'Grant'=>[29,4,'Doctor'], 'Roberts'=>[32,1,'Priest'], 'Johnson'=>[29,3,'MD'], 'Harper'=>[23,2,'Student'] ); # sort by age and print foreach my $name ( sort { $bar{$b}[0]<=>$bar{$a}[0] } keys %bar ) { my ($age,$pets,$prof) = @{$bar{$name}}; print "Name: $name\nAge: $age\nPets: $pets\nProf: $prof\n"; } # end-foreach exit;
This returns
Name: Roberts
Age: 32
Pets: 1
Prof: Priest
Name: Johnson
Age: 29
Pets: 3
Prof: MD
Name: Grant
Age: 29
Pets: 4
Prof: Doctor
Name: Harper
Age: 23
Pets: 2
Prof: Student
But I would like to sort by age first and then by number of pets second. The above code doesnt always return in the correct order for the pets part.

Does anyone know a way to achieve this?

Cheers,
Reagen

Replies are listed 'Best First'.
Re: Double sort in hash values
by ikegami (Patriarch) on Nov 22, 2004 at 15:13 UTC

    Change
    sort { $bar{$b}[0]<=>$bar{$a}[0] }
    to
    sort { $bar{$b}[0]<=>$bar{$a}[0] || $bar{$b}[1]<=>$bar{$a}[1] }

      Let's explain what's going on here.

      The <=> operator returns -1, 0, or 1 depending on the comparison results. If the terms being compared are equal, zero is returned. Zero also happens to be what Perl thinks of as false. This is important.

      The logical short circuit 'or' operator '||' evaluates the left hand side for truth. If the lefthand side evaluates to false, 'or' then looks to the righthand side. This is also important.

      Putting it all together... If the lefthand comparison contains unequal terms, the comparison operator returns -1 or 1, both of which are 'true', and the righthand comparison never gets evaluated. If the lefthand comparison contains equal terms, the <=> opearator returns 0 (false), so the || (or) operator then evaluates the expression on the righthand side.

      You can chain together multiple expressions this way. The expressions with higher priority should be on the left, and the lower priority should be on the right. The ones further to the right will only be evaluated if the ones further to the left all evaluate to 'equal'.


      Dave

      cool. thanks!