in reply to Sorting on Exists

Assuming a recent version of Perl, I think your original code would work if the first sort were:
sort { exists $b->{vtype_ug} <=> exists $a->{vtype_ug} }
(untested, but I think it's the right idea)

A sort sub should return positive if $a is greater than $b, 0 if they are equal, and negative if $b is greater than $a. So if you want items with vtype_ug to always sort before items that don't have it, you need to return -1 if you find it only in $a, 1 if you find it only in $b, or 0 if it is in both or neither.

According to sort's documentation, in Perl 5.7 and newer sorts are "stable", which means that if two items are equal they'll stay in the same order. This should ensure that two sorts work. However, as others have mentioned, you can expect better performance and better portability if you use one sort sub that does both comparisons:

sort { (exists $b->{vtype_ug} <=> exists $a->{vtype_ug}) || ($a->{total_rate} <=> $b->{total_rate}) }

Update: bart is right on all points, and I've corrected them above. Thanks!

Replies are listed 'Best First'.
Re^2: Sorting on Exists
by bart (Canon) on Sep 09, 2006 at 20:18 UTC
    Assuming a recent version of Perl, I think your original code would work if the first sort were:
    sort { (exists $a->{vtype_ug}||0) <=> (exists $b->{vtype_ug}||0) }
    You've got the compare function giving the opposite result than desired, but yes, it does work (in 5.8.8, at least), with this code:
    @sorted = sort { (exists $b->{vtype_ug}||0) <=> (exists $a->{vtype_ug} +||0) } sort { $a->{total_rate} <=> $b->{total_rate} } @arr;
    Actually, there's no need for that || 0 as exists returns a boolean, thus, that's safe to use as 0 when it returns false. So the next works too, without any warnings:
    @sorted = sort { exists $b->{vtype_ug} <=> exists $a->{vtype_ug} } sort { $a->{total_rate} <=> $b->{total_rate} } @arr;