Nikson Nikson - 5 months ago 21
Perl Question

Sort mixed text lines (alphanum) in Perl

I have txt file with every line structure like this:


And have to sort file lines based on seqNo (min to max). Sequence number can be virtually any number starting from zero. Any idea how can it be done in efficient way?


The Schwartzian Transform as suggested in Toto's answer is probably the fastest way to sort your lines here. But you said you're a Perl newbie, and I like to show how the lines can be sorted traditionally.

Perl has a sort function that sorts a list simply by alphabet. But you can supply a custom comparison function and let sort use your function to compare the elements. During its operation sort must continuously compare two elements (=lines) of your list and decide which one is greater or lesser or whether they are equal.

If you supply a comparison function, sort will call it with two such elements as the parameters $a and $b. You do not need to must not declare $a and $b, they are magic and just there. Your comparison function could look like this:

sub by_seqNo
    # extract the sequence number from $a and $b
    my ($seqA) = ($a =~ /seqNo:U\((\d+)/);
    my ($seqB) = ($b =~ /seqNo:U\((\d+)/);

    # numerically compare the sequence numbers (returns -1/0/+1)
    $seqA <=> $seqB;

The first two lines extract the numbers after seqNo:U( and store them as $seqA and $seqB. The third line compares these sequence numbers as integers and returns that result. Combined with the sort function this gives:

my @sorted = sort by_seqNo @lines;

The reason why the Schwartzian Transform (ST) is faster than this solution is because the ST does the (expensive) operation of extracting the seqNo from your lines exactly once for each line. The "traditional" approach on the other hand extracts the seqNo twice for each comparison.