You can sort this by providing a custom comparator. It appears that you want a two level value as the sorting key, so your custom comparator would derive the key for a row and then compare that:
# You want karyotypical sorting on the first element,
# so set up this hash with an appropriate normalized value
# per available input:
my %karyotypical_sort = (
1 => 1,
...
X => 100,
);
sub row_to_sortable {
my $row = shift;
$row =~ /chr(.+):(\d+)-/; # assuming match here! Be careful
return [$karyotypical_sort{$1}, $2];
}
sub sortable_compare {
my ($one, $two) = @_;
return $one->[0] <=> $two->[0] || $one->[1] <=> $two->[1];
# If first comparison returns 0 then try the second
}
@lines = ...
print join "\n", sort {
sortable_compare(row_to_sortable($a), row_to_sortable($b))
} @lines;
Since the calculation would be slightly onerous (string manipulation is not free) and since you are probably dealing with a lot of data (genomes!) it is likely you will notice improved performance if you perform a Schwartzian Transform. This is performed by precalculating the sort key for the row and then sorting using that and finally removing the additional data:
@st_lines = map { [ row_to_sortable($_), $_ ] } @lines;
@sorted_st_lines = sort { sortable_compare($a->[0], $b->[0]) } @st_lines;
@sorted_lines = map { $_->[1] } @sorted_st_lines;
Or combined:
print join "\n",
map { $_->[1] }
sort { sortable_compare($a->[0], $b->[0]) }
map { [ row_to_sortable($_), $_ ] } @lines;