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

Fellow Monasterians,

I'm trying to sort an AoH first by one key and then another 'under' that. So:

my $sqldata = [ { 'under' => '2', 'order' => '2' }, { 'under' => '2', 'order' => '1' }, { 'under' => '1', 'order' => '2' }, { 'under' => '1', 'order' => '3' }, { 'under' => '1', 'order' => '1' } ]; my $AoH = [ sort { $a->{under} <=> $b->{under} } @$sqldata ];

and I want to end up with:

my $sqldata = [ { 'under' => '1', 'order' => '1' }, { 'under' => '1', 'order' => '2' }, { 'under' => '1', 'order' => '3' }, { 'under' => '2', 'order' => '1' }, { 'under' => '2', 'order' => '2' } ];

I thought I had found it in sorting a hash by keys, according to preference, but that appears to be a different deal. Thanks.


—Brad
"The important work of moving the world forward does not wait to be done by perfect men." George Eliot

Replies are listed 'Best First'.
Re: Sorting AoH by two keys
by nothingmuch (Priest) on Jul 08, 2005 at 21:41 UTC
    <=>, the spaceship operator, has an interesting property - when the two sides are equal, it returns 0. This is very useful, because then you say:

    my $AoH = [ sort { $a->{under} <=> $b->{undef} || $a->{order} <=> $b->{order} } @$sqldata ];
    This works because || evaluates it's left side, and if it's false (0 is false), it evaluates the right too. It returns the first true value it finds (or the last false one if it didn't).

    Let's compare 2,2 and 2,1:

    (2 <=> 2) == 0 so 0 || 2 <=> 1 evaluates to 2 <=> 1 (2 <=> 1) == 1 # the answer we wanted

    BTW, I noticed you have 'sqldata'... This smells like you're doing fetching the entire result table as an array ref, and then sorting it... Why not make it into

    select ... order by under, order;
    This stuff is better (and probably more efficiently) handled on the server side.

    Update: tphyahoo was right - but it was no typo... I wrote down $a twice when I should have written $b. Sorry!

    -nuffin
    zz zZ Z Z #!perl

      Perfect, thanks for the 'tutorial.' After I saw your solution I realized that I was basically asking the same question as I did in How to sort a AoH reference, but I wasn't understanding the || as I stared at it. Now I see how it works in conjunction with the <=>. Copying code out of a book might get something to work, but it doesn't help in the long run unless it is truly understood.

      Which is why I didn't want to rely solely on the SELECT...ORDER BY. (BTW, you are quite perceptive).


      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
      nothingmuch, although the OP said this works, it didn't work for me.

      UPDATE: it was a typo. I think nothingmuch meant

      my $sorted = [ sort { $a->{under} <=> $b->{under} || $a->{order} <=> $b->{order} } @$aoh ];
Re: Sorting AoH by two keys
by tphyahoo (Vicar) on Jul 09, 2005 at 16:28 UTC
    Another way to do it... but it only works if all the numbers have the same number of digits.... :) but anyway...
    my $sorted = [ sort { $a->{under} . $a->{order} cmp $b->{under} . $b->{order} } @$aoh ];
    I wonder if there's some way to hack this into something that actually would work, using sprintf %dd or something?... Actually, I don't wonder. Never mind...