令人困惑的perl中的"排序"语法

Rij*_*one 0 perl

我今天开始学习Perl并发现了这个非常有趣的教程.但是,对于我的生活,我无法绕过这段代码.

print " $_: $created{$_}" for(sort({$created{$b} <=> $created{$a}} keys %created));
Run Code Online (Sandbox Code Playgroud)

这是什么类型的?更具体地讲,什么是变量$a和$b?我试过浏览文档,但不能说它有帮助.任何支持将不胜感激.

Jos*_*hua 9

这里发生了一些事情.首先,我将解决后缀循环;

say $_ for ('foo', 'bar', 'baz');
Run Code Online (Sandbox Code Playgroud)

这在语义上与执行此操作相同

for ('foo', 'bar', 'baz') { say $_ }
Run Code Online (Sandbox Code Playgroud)

现在进行排序.默认情况下,Perl sort按字母顺序排序

sort (20, 3, 100);  # RESULT: (100, 20, 3)
Run Code Online (Sandbox Code Playgroud)

Perl提供了一种按字母顺序(cmp)或数字(<=>)显式比较的方法.

20 cmp 3;  # RESULT: -1 (means: Less)
20 <=> 3;  # RESULT:  1 (means: More)
20 <=> 20; # RESULT:  0 (means: Same)
Run Code Online (Sandbox Code Playgroud)

所以你可以在一个sort块中使用这些运算符,但是你把它放在运算符的哪一边?这是特殊$a和$b变量的来源.

sort { $a <=> $b } (20, 3, 100);  # RESULT: (3, 20, 100)
Run Code Online (Sandbox Code Playgroud)

这也是为什么你不应该手动分配值,$a或者$b如果你这样做,sort将无法正常运行!

所以把它们放在一起,你的排序是按照数字对应的值对Hash的键进行排序

my %hash = ( twenty => 20, three => 3, onehundred => 100 ); 

for ( sort { $hash{$a} <=> $hash{$b} } keys %hash ) {
    say "$_: %hash{$_}"
}
Run Code Online (Sandbox Code Playgroud)

输出

three: 3
twenty: 20
onehundred: 100
Run Code Online (Sandbox Code Playgroud)

您也可以{ $b <=> $a }反向排序.

如果这一切看起来晦涩难懂,那就有点儿了.我建议使用类似于Sort::Key大多数排序需求的模块......或者Sort::Naturally如果那更像你所追求的那样.


sim*_*que 5

print " $_: $created{$_}" 
    for ( sort { created{$b} <=> $created{$a} } keys %created );
Run Code Online (Sandbox Code Playgroud)

这使用了后修复形式for.在Perl,for并且foreach是相同的.两者都可以与C风格的for语法以及较短的foreach样式语法一起使用.

我们可以将此循环重写为以下更详细的版本.

foreach ( sort { created{$b} <=> $created{$a} } keys %created ) {
    print " $_: $created{$_}";
}
Run Code Online (Sandbox Code Playgroud)

接下来,我们来看看$_.它被称为主题,如果没有给出其他变量,它将被用作Perl中很多东西的默认输入.在foreach循环中,如果没有使用迭代变量,则括号中列表的每个元素都会结束$_.同样,为了清楚起见,可以重写.

foreach my $elem ( sort { created{$b} <=> $created{$a} } keys %created ) {
    print " $elem: $created{$elem}";
}
Run Code Online (Sandbox Code Playgroud)

现在让我们来看看sort.这两个变量$a,并$b在全局变量总是在那里Perl编写的.它们是为sort语句后面的块保留的.

sort { BLOCK } LIST
Run Code Online (Sandbox Code Playgroud)

$a并$b包含列表中的两个值,这些值在块中进行比较.该块的行为类似于匿名函数(在其他语言中称为lambda),并且后面没有逗号.或者,您可以将名称sub的名称作为带有引号的裸字放在那里.再说一遍,没有逗号.

sub bubbly_sort { $a <=> $b }
sort bubbly_sort 3, 2, 1;
Run Code Online (Sandbox Code Playgroud)

该<=>运营商做数值比较.这两个值和收益进行比较-1,0或1.

sort { $b <=> $a } LIST
Run Code Online (Sandbox Code Playgroud)

这将对LIST中的值进行数字降序排序,因此最高值首先出现.$a <=> $b会提升.

sort { created{$b} <=> $created{$a} } keys %created
Run Code Online (Sandbox Code Playgroud)

该keys关键字为您提供散列内的密钥的无序列表%created.您在块中的块sort比较%created哈希中这些键后面的值,并对键降序进行排序.所以你得到一个排序键列表.

其余代码只打印出该排序键列表的键/值列表.

值得注意的是,输出全部在一行上,因为之后没有换行符print.


您发布的精简版本比我在此答案中显示的长版本更具可读性.但它有适当的缩进和括号的使用.

print " $_: $created{$_}" 
    for sort { created{$b} <=> $created{$a} } keys %created;
Run Code Online (Sandbox Code Playgroud)

与

print " $_: $created{$_}" for(sort({$created{$b} <=> $created{$a}} keys %created));
Run Code Online (Sandbox Code Playgroud)

与

foreach ( sort { created{$b} <=> $created{$a} } keys %created ) {
    print " $_: $created{$_}";
}
Run Code Online (Sandbox Code Playgroud)

在我看来,第一个版本读起来最像英语句子,这很好.干净,可读的代码应始终是优秀开发人员的首要任务.

  • 请注意,官方语法是`sort SUBNAME LIST`,并且传递子例程引用不是记录的选项. (2认同)