I have a hash like the following:
my %hash=( '(293 to 296)' => 2,
'(3118 to 3121)' => 2,
'(330 to 333)' => 2,
'(2126 to 2129)' => 2,
'(1999 to 2002)' => 2,
'(2138 to 2141)' => 9,
'(771 to 774)' => 4,
'(2016 to 2019)' => 1,
'(888 to 891)' => 5,
'(3102 to 3105)' => 1,
);
I want to sort my hash using keys, where keys contains brackets. I have tried the following code,
foreach $key(sort {$b <=> $a} keys %hash)
{
print $key;
}
and I got the following, which is not numerically sorted:
(888 to 891)(2016 to 2019)(293 to 296)(3118 to 3121)(3102 to 3105)(330 to 333)(1999 to 2002)(2126 to 2129)(2138 to 2141)(771 to 774)
I expect an output, which is numerically sorted as below. Please suggest me a way to achieve the following:
(293 to 296)
(330 to 333)
(771 to 774)
(888 to 891)
(1999 to 2002)
(2016 to 2019)
(2126 to 2129)
(2138 to 2141)
(3102 to 3105)
(3118 to 3121)
sort works by passing $a and $b into a function, and returning -1, 0 or +1.
The simplest - sorting on the first number - would go like this:
sort { $a =~ s/.(\d+).*/$1/r <=> $b =~ s/.*(\d+).*/$1/r } keys %hash
This extracts the first numeric value from each key, compares and returns that comparison value.
Of course, if your ranges overlap, this won't work the way you want - you'll have to get a bit more complicated - if you have:
100 to 200 150 to 180 120 to 205
How should they be sorted? Either way though - you write a subroutine that 'works' on $a and $b and performs the comparison. A useful trick here is that the 'standard' sort operators - <=> and cmp - return zero, and thus can be shortcutted with ||.
So:
sub compare_numbers {
my @a = $a =~ m/(\d+)/g;
my @b = $b =~ m/(\d+)/g;
return ( $a[0] <=> $b[0]
|| $a[1] <=> $b[1] )
}
If the first comparison is zero, then the second is evaluated.
Or you can calculate the intermediate value:
sub compare_numbers {
my @a = $a =~ m/(\d+)/g;
my @b = $b =~ m/(\d+)/g;
return ( ($a[1] - $a[0] / 2 + $a[0]) <=> ($b[1] - $b[0] / 2 + $b[0])
}
You would use either of these in a similar way to above:
sort compare_numbers keys %hash
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With