I have the following array of strings:

``Expt5_Expt12Expt5_Expt1Expt12_Expt2Expt11_Expt8Expt1_Expt2Expt10_Expt1Expt10_Expt4Expt11_Expt1``

I want to sort these strings by the first number and in second priority by the second number so that I have a list like that:

``Expt1_Expt2Expt5_Expt1Expt5_Expt12Expt10_Expt1Expt10_Expt4Expt11_Expt1Expt11_Expt8Expt12_Expt2``

I only found solutions to sort only by the first number OR by the second. I tried some things with regex-expressions and sort-function but I didn't come to a solution.

Sorting by function is really easy. The function has to return -1, 0 or 1 depending if `\$a` and `\$b` are before or after. (As noted in comments - it can be any positive or negative value - the key point is whether the elements are before or after each other).

`\$a` and `\$b` are 'special' variables used specifically for perl and sorting. They therefore don't need to be declared, and are a really bad idea to use for other stuff in your code. But then, who uses single letter vars anyway?

``````#!/usr/bin/env perl
use strict;
use warnings;

sub custom_sort {
my ( \$a1, \$a2 ) = ( \$a =~ m/(\d+)/g );   #extract the numeric elements
my ( \$b1, \$b2 ) = ( \$b =~ m/(\d+)/g );

return ( \$a1 <=> \$b1     #return the result of this comparison
|| \$a2 <=> \$b2 );  #unless it's zero, then we return the result of this.
}

my @list = <DATA>;
print sort custom_sort @list;

__DATA__
Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
``````

You can make this more concise, but the essence is this:

• extract the first and second values.
• Then use the `||` operator - so that if `\$a1 <=> \$b1` is zero, it evaluates the second part of the expression.
• `<=>` is a 'less than, equal to, greater than' operator which returns -1, 0 or 1 based on numeric comparison. For strings you can use `cmp` to do the same thing.

(You can print these if you wish to debug how this sort is 'working' for each comparison, which is really handy if you're doing something complicated)

This is broadly the same solution as others have posted, but it is made more concise by the use of `map`

``````use strict;
use warnings;

my @data = <DATA>;

print sort {
my @ab = map [ /\d+/g ], \$a, \$b;
\$ab[0][0] <=> \$ab[1][0] or \$ab[0][1] <=> \$ab[1][1];
} @data;

__DATA__
Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
``````

### output

``````Expt1_Expt2
Expt5_Expt1
Expt5_Expt12
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
Expt11_Expt8
Expt12_Expt2
``````

use Sort::Key::Multi;

``````use Sort::Key::Multi qw(i2_keysort); #i2 means two integer keys

my @sorted = i2_keysort { /(\d+)\D+(\d+)/ } @data;
``````

Top