Reputation: 247
I am trying to figure out how to sort list of file names in Perl.
Each file is a PDF file that I am merging into a single pdf using Perl's PDF::Reuse
Each pdf file name has two unique identifier. 1) is the account ID & 2) report type.
Example:
C1234.lfs.pdf
C1234 = account id lfs = report type.
each account could have several reports that need to be in a specific order.
How can I specify the order of report types? I want to use a config file where the script would look to see what order to sort each accounts reports before merging to 1 pdf file. Order I would like is:
AcctId.lau.pdf AcctId.lsm.pdf AcctId.lad.pdf AcctId.lfs.pdf AcctId.lbe.pdf
@PDFS = (<*l*.pdf>);
@REVERSED_LIST = reverse(@PDFS);
prFile($OutPut);
for my $pdf (@REVERSED_LIST) {
next if($pdf eq $OutPut);
&Logit("Adding $pdf to $OutPut");
prDoc($pdf);
}
prEnd();
Sorry if I am not explaining this correctly any help and suggestions are appreciated.
New code being tested not giving correct order.
@PDFS = (<*l*.pdf>);
my %lsfOrder = (lua=>0, lsm=>1, lfw=>2);
@SORTED = map { $_->[0] } # Take just the original file name
sort {
$a->[1] cmp $b->[1] ?
$a->[1] cmp $b->[1] : # compare by account id if different
$lsfOrder{$a->[2]} <=> $lsfOrder{$b->[2]}
}
map {
[ $_, split('.', $_) ] # split into id/type once at the beginning
} @PDFS;
prFile($OutPut);
for my $pdf (@SORTED) {
next if($pdf eq $OutPut);
&Logit("Adding $pdf to $OutPut");
#print "Adding $pdf to $OutPut\n";
prDoc($pdf);
}
prEnd();
Upvotes: 1
Views: 1362
Reputation: 1687
Perl sort takes a code block as its first argument that can control the sorting. There are two special variables defined, '$a', and '$b' which are two elements to compare. From there, you would use cmp
and <=>
to compare different parts of the strings and return whether a is less-than, greater-than or equal-to b. The sort
function picks $a and $b based on its internal sorting algorithm from your list. E.g.:
@SORTED = sort {
my @a = split ".", $a;
my @b = split ".", $b;
if ($a[0] cmp $b[0] != 0) { return $a[0] cmp $b[0] }
my %lsfOrder = (lau=>0, lsm=>1, lad=>2, lfs=>3, lbe=>4);
my $lsfA = $lsfOrder{$a[1]};
my $lsfB = $lsfOrder{$b[1]};
return $lsfA <=> $lsfB;
} @PDFS;
The code above splits the file names on the '.'. Then it compares the first element (the account id) and if they aren't the same, returns the result of that comparison. Otherwise it returns the result of comparing the report type. It converts the lsf into an integer in the order you've given, then compares those integers.
Edit: Joe Z has good suggestions for speed-ups. To summarize:
my %lsfOrder = (lau=>0, lsm=>1, lad=>2, lfs=>3, lbe=>4);
@SORTED = map { $_->[0] } # Take just the original file name
sort {
$a->[1] cmp $b->[1] ?
$a->[1] cmp $b->[1] : # compare by account id if different
$lsfOrder{$a->[2]} <=> $lsfOrder{$b->[2]} # otherwise, compare by report type in specific order
}
map {
[ $_, split('.', $_) ] # split into id/type once at the beginning
} @PDFS;
Upvotes: 2