Search code examples
perlsortingperl-module

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?


Solution

  • 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