Reputation: 1018
I have a follow up question to my earlier post Sorting file names by numeric value.
The solution was this piece of code:
opendir(XMLDIR,$xmldirname);
my @files = sort {substr($a, 0, index($a, '.')) <=> substr($b, 0, index($b, '.'))} readdir(XMLDIR);
I don't really understand what the whole sort {...} in front of the readdir is doing, or rather, HOW it is doing what it is doing. Of course I can see that two values are compared to each other. But what kind of syntax construct is this whole thing? Where is $a and $b coming from? Under what heading could I look that up in a Perl book? Is this a special thing that works only with sort {} or are there other ways of using this construct?
Upvotes: 4
Views: 254
Reputation: 385590
The adopted syntax of sort
is
sort BLOCK LIST
The expression represented by LIST
is to return the list of values to sort. This is readdir(XMLDIR)
in your case. It returns the list of the names of the files in the directory.
The BLOCK
is the interesting part. It represents code in curlies that's called by the sorting algorithm to compare to of the elements to sort. The elements to compare are provided as $a
and $b
, and the code should evaluate to one of the following:
$a
should be placed before $b
,$a
should be placed relative to $b
, or$a
should be placed after $b
.substr($a, 0, index($a, '.'))
extracts the portion of the file name before the first .
. In this case, that extracts the number in the file name.
Then, the numbers extracted from the two file names are compared numerically by <=>
, retuning -1
, 0
or +1
as described above.
Note that your code will warn because it doesn't take into account that readdir
will return .
and ..
. I addressed this by adding an answer to your original question.
Upvotes: 6
Reputation: 699
Doing this: sort @arrayofnumbers
Is the same as: sort { $a cmp $b } @arrayofnumbers
Where $a and $b are the two items being compared at each step of the sort. The return value of the block of code needs to be an integer where 0 means that the items are the same, <0 means that $a is less than $b, and >0 means that $a is greater than $b. Usually this is done with "cmp" for strings and <=> for numbers.
So the part that is confusing you, the stuff between the braces, is really just a block of code that will return -1, 0, or +1 depending on how you want the two items to compare.
You can do a lot of stuff in there, eg you can see the order of the compares by doing something like this:
sort { print "$a cmp $b = ".($a cmp $b)."\n"; return $a cmp $b } (2,19,29,39);
Yielding:
2 cmp 19 = 1
29 cmp 39 = -1
19 cmp 29 = -1
29 cmp 2 = 1
One thing that gets folks is that the default compare is a string compare. So if you do:
print join(',', sort 2,19,39,29)."\n";
You'll get : 19,2,29,39
To do an integer compare you need to do:
sort { $a <=> $b } (2,19,39,29)
Upvotes: 1
Reputation: 7912
This is invoking sort
with a block argument. Blocks are used in several other Perl built ins including map
and grep
.
A block argument is a way of defining your own code for the function to execute. sort
uses the block to compare two values from the list being sorted, represented by $a
and $b
.
Using prototypes, you can define your own subroutines to work in a similar manner:
sub block_exec(&@) {
my $block = shift;
for (@_) {
&$block;
}
}
block_exec { print "block! $_\n"; } (1..10);
Upvotes: 4
Reputation: 8926
$a
and $b
are provided by sort
to the comparison function passed to it. sort
acts on an array, which is produced in this instance by readdir
. sort
repeatedly applies the unnamed comparison routine to the entries in the array, rearranging them until they're in order.
Upvotes: 1
Reputation: 1380
Under what heading could I look that up in a Perl book?
Under 'sort'
http://perldoc.perl.org/functions/sort.html
That line is defining a custom method of comparing the two values (used to create the sorted list) which is different from the default comparisons. $a and $b are the two values being compared at a time in the sort.
Upvotes: 1