我在之前的帖子Sorting file names by numeric value中有一个跟进问题。
解决方案就是这段代码:
opendir(XMLDIR,$xmldirname);
my @files = sort {substr($a, 0, index($a, '.')) <=> substr($b, 0, index($b, '.'))} readdir(XMLDIR);
我真的不明白readdir前面的整个排序{...}正在做什么,或者更确切地说,它是如何做它正在做的事情。当然,我可以看到两个值相互比较。但是整个事情是什么样的语法结构? $ a和$ b来自哪里?我可以在Perl书中看到哪些标题?这是一个特殊的东西,只适用于sort {},还是有其他方法可以使用这个构造?
答案 0 :(得分:7)
sort
采用的语法是
sort BLOCK LIST
LIST
表示的表达式是返回要排序的值列表。在您的情况下,这是readdir(XMLDIR)
。它返回目录中文件名的列表。
BLOCK
是有趣的部分。它代表curlies中的代码,由排序算法调用以与要排序的元素进行比较。要比较的元素以$a
和$b
提供,代码应评估为以下之一:
$a
应放在$b
之前$a
放置$b
或$a
之后应放置$b
,则为正值。 substr($a, 0, index($a, '.'))
在第一个.
之前提取文件名的一部分。在这种情况下,它会提取文件名中的数字。
然后,从<=>
数字比较从两个文件名中提取的数字,如上所述重新调整-1
,0
或+1
。
请注意,您的代码会发出警告,因为它没有考虑readdir
将返回.
和..
。我通过在原始问题中添加answer来解决此问题。
答案 1 :(得分:5)
这是使用sort
参数调用block。块包含在其他几个Perl内置文件中,包括map
和grep
。
块参数是一种为要执行的函数定义自己的代码的方法。 sort
使用该块比较要排序的列表中的两个值,由$a
和$b
表示。
使用prototypes,您可以定义自己的子程序以类似的方式工作:
sub block_exec(&@) {
my $block = shift;
for (@_) {
&$block;
}
}
block_exec { print "block! $_\n"; } (1..10);
答案 2 :(得分:1)
在哪个标题下,我可以在Perl书中看到它?
在&#39;排序&#39;
http://perldoc.perl.org/functions/sort.html
该行定义了一种比较两个值(用于创建排序列表)的自定义方法,该方法与默认比较不同。 $ a和$ b是排序中一次比较的两个值。
答案 3 :(得分:1)
$a
和$b
由sort
提供给传递给它的比较函数。 sort
作用于数组,该数组在此实例中由readdir
生成。 sort
重复将未命名的比较例程应用于数组中的条目,重新排列它们直到它们按顺序排列。
答案 4 :(得分:1)
这样做:排序@arrayofnumbers
与:{$ a cmp $ b} @arrayofnumbers
其中$ a和$ b是在排序的每个步骤中比较的两个项目。 代码块的返回值需要是一个整数,其中0表示项目相同,&lt; 0表示$ a小于$ b,&gt; 0表示$ a大于$ b。通常用字符串的“cmp”和&lt; =&gt;来完成。数字。
所以令你困惑的部分,大括号之间的东西,实际上只是一个代码块,它将返回-1,0或+1,具体取决于你想要比较两个项目的方式。
你可以在那里做很多事情,例如你可以通过这样的方式看到比较的顺序:
sort { print "$a cmp $b = ".($a cmp $b)."\n"; return $a cmp $b } (2,19,29,39);
产量:
2 cmp 19 = 1
29 cmp 39 = -1
19 cmp 29 = -1
29 cmp 2 = 1
让人们知道的一件事是默认比较是字符串比较。 所以如果你这样做:
print join(',', sort 2,19,39,29)."\n";
你会得到:19,2,29,39
要进行整数比较,您需要这样做:
sort { $a <=> $b } (2,19,39,29)