Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is this Perl syntax construct?

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?

like image 779
jackthehipster Avatar asked Aug 11 '14 14:08

jackthehipster


2 Answers

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 negative value if $a should be placed before $b,
  • Zero if it doesn't matter matter where $a should be placed relative to $b, or
  • A positive value if $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.

like image 112
ikegami Avatar answered Sep 28 '22 01:09

ikegami


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);
like image 26
RobEarl Avatar answered Sep 28 '22 01:09

RobEarl