cucurbit cucurbit - 29 days ago 11
Perl Question

Sort hash attending to two parameters

I have a hash with the keys in the following format:

scaffold_902_159
scaffold_2_1980420
scaffold_2_10
scaffold_10_402


I want to print out the hash sorted in the following format:

scaffold_2_10
scaffold_2_1980420
scaffold_10_402
scaffold_902_159


So first I have to order numerically attending to the first number and then attending to the last one. I don't want a regular expression searching for "scaffold_" since this may vary. I mean, I can have the hash with other format like "blablabla_NUMBER_NUMBER, or blablablaNUMBER_NUMBER". The last part of the key _NUMBER, is the only thing that is permanent.

I've this code but only sorts numerically attending to the first number:

my @keys = sort {
my ($aa) = $a =~ /(\d+)/;
my ($bb) = $b =~ /(\d+)/;
$aa <=> $bb;
} keys %hash;
foreach my $key (@keys) {
print $key;
}


Any suggestion?

Answer

Sort::Naturally to the rescue!

#!/usr/bin/perl
use strict;
use warnings;
use Sort::Naturally qw(nsort);
my %hash = (
                scaffold_902_159 => 'v1',
                scaffold_2_1980420 => 'v2',
                scaffold_2_10 => 'v3',
                scaffold_10_402 => 'v4',
            );
print "$_\n" for nsort keys %hash;

Output:

scaffold_2_10
scaffold_2_1980420
scaffold_10_402
scaffold_902_159

As per your query, tried out some keys which did not have number in middle.

#!/usr/bin/perl
use strict;
use warnings;
use Sort::Naturally qw(nsort);
my @keys = qw(
    should_come_last_9999_0
    blablabla_10_403
    scaffold_902_159
    scaffold_2_1980420
    scaffold_2_10
    scaffold_10_402
    blablabla902_1
    blablabla901_3
);
print "$_\n" for nsort @keys;

Output:

blablabla_10_403
blablabla901_3
blablabla902_1
scaffold_2_10
scaffold_2_1980420
scaffold_10_402
scaffold_902_159
should_come_last_9999_0