Quote:
> sub mysort {
> my ($gtl);
> if ( $hash{$a} == $hash{b})
> $gtl = $a cmp $b;
> } else {
> $gtl = $hash{$a} <=> $hash{$b};
> }
> return $gtl;
> }
There's a big efficiency problem in that code:
you compare $hash{$a} to $hash{$b} twice
(except in cases where they happen to be equal).
If you compare them using <=> first, then you don't
have to compare them again.
First, rewrite so that the branches are swapped:
if ( $hash{$a} != $hash{b} ) {
$gtl = $hash{$a} <=> $hash{$b};
} else {
$gtl = $a cmp $b;
}
Note that != and <=> evaluate identically in a boolean
context. So use <=> for the boolean test:
if ( $hash{$a} <=> $hash{b} ) {
$gtl = $hash{$a} <=> $hash{$b};
} else {
$gtl = $a cmp $b;
}
Now cache the value of that comparison:
$gtl = $hash{$a} <=> $hash{$b};
if ( $gtl ) {
} else {
$gtl = $a cmp $b;
}
Which of course is the same as:
$gtl = $hash{$a} <=> $hash{$b};
if ( ! $gtl ) {
$gtl = $a cmp $b;
}
A nice shorthand for this situation, which happens
to crop up a lot, is:
$gtl = $hash{$a} <=> $hash{$b};
$gtl ||= $a cmp $b;
Of course, if that's all you're doing, you may as well say:
$gtl = $hash{$a} <=> $hash{$b}
|| $a cmp $b;
So mysort actually looks like this:
sub mysort {
my $gtl;
$gtl = $hash{$a} <=> $hash{$b} || $a cmp $b;
return $gtl;
}
Which is obviously nothing more than
sub mysort {
$hash{$a} <=> $hash{$b} || $a cmp $b;
}
Which means you can skip the subroutine altogether:
for (
sort { $hash{$a} <=> $hash{$b} || $a cmp $b } keys %hash
) {
....
}
I'd like to commend Tony for bringing up the good point
that the hash can be sorted by keys when the values are
equal.
--
John Porter