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

This seems to be a unique problem, but forgive me if it was addressed before. I'm trying to perform a hash sort by 2 values, but the stipulation is I need 1 of those values to be reverse sorted. Here's what I have (excuse my verbosity, I wanted to be very explicit):
my @hashes = ( {name=>'a', flag=>1}, {name=>'a', flag=>0}, {name=>'b', flag=>1}, {name=>'c', flag=>0}, {name=>'b', flag=>0} ); @hashes = sort { $a->{name} cmp $b->{name} or $a->{flag} cmp $b->{flag} } @h +ashes; The order that this gives me is: name: a flag: 0 name: b flag: 0 name: c flag: 0 name: a flag: 1 name: b flag: 1 But what I want is: name: a flag: 1 name: b flag: 1 name: a flag: 0 name: b flag: 0 name: c flag: 0
As you can see, if I simply call reverse on the list, it will also reverse the name field order, which I need to retain. I was wondering if there was some kind of magic I am overlooking to get the proper results.

Thanks in advance,
Andy.

Replies are listed 'Best First'.
Re: Sort hash values with one key in reverse
by Limbic~Region (Chancellor) on Apr 11, 2006 at 16:41 UTC
    timecatalyst,
    First you need to make the flag key the first sort criteria, second ensure it is descending order not ascending, third use the spaceship operator instead of cmp because you want to treat them numerically (see perlop for details), and finally use a secondary sort by name.
    @hashes = sort { $b->{flag} <=> $a->{flag} || $a->{name} cmp $b->{nam +e} } @hashes;
    You may also want to consider if the Schwartzian Transform is appropriate.

    Cheers - L~R

      Oh! Thanks a bunch, Limbic! My big problem was the treatment of $a and $b. I don't think I fully understood how they work up until now. That shines a lot of light on things.

      Thanks again!
Re: Sort hash values with one key in reverse
by salva (Canon) on Apr 11, 2006 at 16:53 UTC
    use Sort::Key::Multi qw(ris_keysort); # ris => reverse integer, string my @sorted = ris_keysort { $_->{flag}, $_->{name} } @hashes;