What is this Perl syntax construct?

I have the following question to my previous post Sort file names by numerical 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 really don’t understand what the whole view {...} is doing in front of readdir, or rather, HOW it does what it does. Of course, I see that the two values ​​are compared with each other. But what is this syntax construct? Where do $ a and $ b come from? Under what heading can I see this in a Perl book? Is this a special thing that only works with sort {}, or are there other ways to use this construct?

+5
source share
5 answers

The accepted syntax is sort -

 sort BLOCK LIST 

The expression represented by LIST should return a list of sortable values. This is readdir(XMLDIR) in your case. It returns a list of file names in the directory.

BLOCK is an interesting part. It represents the code in curlies, which is called by the sorting algorithm to compare with the elements to be sorted. Elements for comparison are represented as $a and $b , and the code must be evaluated with one of the following:

  • A negative value if $a should be placed before $b ,
  • Zero if it doesn't matter where $a should be placed relative to $b or
  • Positive if $a should be placed after $b .

substr($a, 0, index($a, '.')) extracts the part of the file name before the first . . In this case, it retrieves the number in the file name.

Then the numbers extracted from the two file names are numerically compared using <=> , reordering -1 , 0 or +1 , as described above.


Note that your code will warn, because it does not take into account what readdir will return . and .. I turned to this by adding an answer to your original question.

+7
source

This calls sort with block . Blocks are used in several other built-in Perl, including map and grep .

A block argument is a way of defining your own code for the function being performed. sort uses a block to compare two values ​​from the sorted list represented by $a and $b .

Using prototypes , you can define your own routines to work in a similar way:

 sub block_exec(&@) { my $block = shift; for (@_) { &$block; } } block_exec { print "block! $_\n"; } (1..10); 
+5
source

Under what heading can I see this in a Perl book?

In the "sort" section

http://perldoc.perl.org/functions/sort.html

This line defines a custom method for comparing two values ​​(used to create a sorted list), which is different from the default comparison. $ a and $ b are two values ​​that are compared at a time in sorting.

+1
source

$a and $b provided by sort passed comparison function. sort acts on the array that is created in this case with readdir . sort reapplies the unnamed comparison procedure to the entries in the array, rearranging them until they are ok.

+1
source

Doing this: sort @arrayofnumbers
Same thing: sort {$ a cmp $ b} @arrayofnumbers

Where $ a and $ b are two elements that are compared at each sorting step. The return value of the code block must be an integer, where 0 means the elements are the same, <0 means $ a is less than $ b, a> 0 means $ a is more than $ b. This is usually done using "cmp" for strings and <=> for numbers.

Thus, the part that confuses you, the material between the curly braces, is actually just a block of code that will return -1, 0, or +1 depending on how you want to compare the two elements.

You can do many things there, for example, you can see the order of comparisons 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 people get is that the default comparison is string comparison. So if you do this:

print join(',', sort 2,19,39,29)."\n";

You will receive: 19,2,29,39

To perform an integer comparison, you need to do:

sort { $a <=> $b } (2,19,39,29)

+1
source

Source: https://habr.com/ru/post/1200031/


All Articles