困惑"排序" perl中的语法

时间:2017-11-08 13:32:38

标签: perl

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

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

这是什么类型的?更具体地说,变量$a$b是什么? 我尝试了documentation,但不能说它有所帮助。任何支持将不胜感激。

3 个答案:

答案 0 :(得分:9)

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

say $_ for ('foo', 'bar', 'baz');

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

for ('foo', 'bar', 'baz') { say $_ }

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

sort (20, 3, 100);  # RESULT: (100, 20, 3)

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

20 cmp 3;  # RESULT: -1 (means: Less)
20 <=> 3;  # RESULT:  1 (means: More)
20 <=> 20; # RESULT:  0 (means: Same)

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

sort { $a <=> $b } (20, 3, 100);  # RESULT: (3, 20, 100)

这也是您不应该为$a$b手动分配值的原因,因为如果您这样做,sort将无法正常运行!

所以把所有这些放在一起,你的排序是按照相应的以数字方式对Hash的进行排序

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

for ( sort { $hash{$a} <=> $hash{$b} } keys %hash ) {
    say "$_: %hash{$_}"
}

输出

three: 3
twenty: 20
onehundred: 100

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

如果这一切看起来晦涩难懂,那就有点儿了。我建议您使用像Sort::Key这样的模块来满足您的大部分排序需求......或者如果您更喜欢Sort::Naturally,那么可能会enter image description here

答案 1 :(得分:5)

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

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

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

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

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

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

现在让我们看一下sort。两个变量$a$b是Perl中始终存在的全局变量。它们保留在sort语句后面的块中。

sort { BLOCK } LIST

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

sub bubbly_sort { $a <=> $b }
sort bubbly_sort 3, 2, 1;

<=>运算符进行数值比较。它会比较这两个值并返回-101

sort { $b <=> $a } LIST

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

sort { created{$b} <=> $created{$a} } keys %created

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

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

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

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

print " $_: $created{$_}" 
    for sort { created{$b} <=> $created{$a} } keys %created;

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

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

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

答案 2 :(得分:3)

打破它。

这是排序位:

sort({$created{$b} <=> $created{$a}} keys %created)

括号与此无关。

sort { $created{$b} <=> $created{$a} } keys %created

所以这是一种非常标准的排序。

sortsort

第一个参数是一个块......

  

如果指定了SUBNAME,则它会给出一个子例程的名称,该子例程返回一个小于,等于或大于0的整数,具体取决于列表元素的排序方式。 (&lt; =&gt;和cmp运算符在此类例程中非常有用。)SUBNAME可以是标量变量名(unsubscripted),在这种情况下,该值提供要使用的实际子例程的名称(或引用)。您可以使用BLOCK作为匿名的内联排序子例程来代替SUBNAME。

第二个参数是被排序的东西(keys %created)。即哈希中keys的列表。

在子资源中,$a$b是要排序的元素。因此$created{$b} <=> $created{$a}获取密钥并比较散列中与它们关联的值。

因此,sort会输出哈希中的键列表,并按与之关联的值进行排序。

然后传递给后缀for,因此对于每个键,它都会执行某些操作(按值的顺序)。

东西是print " $_: $created{$_}":所以它打印键,然后是冒号,然后是值。