哎呀,同样糟糕......
print map $_->[1],
sort {
$a->[0] cmp $b->[0] ##first element of the array
or $a->[1] cmp $b->[1] }
map [ tr/"MATCH"/"MATCH"/, $_ ], @allmatches;
sort 部分相对简单。
sort { $a->[0] cmp $b->[0] or $a->[1] cmp $b->[1] } ...an array...
数组的每个元素本身就是一个数组 ref,比较对数组 refs 的第一个元素进行字符串比较(cmp),如果它们相等(cmp 返回 0),则第二个元素。
因此,输出是一个排序数组。这留下了两块代码需要剖析。第一行和最后一行。最后一行运行map:
map [ tr/"MATCH"/"MATCH"/, $_ ], @allmatches
这显然是在进行无操作转换,因为tr/// 运算符中的左右字符串是相同的;这有点令人费解。 [更新:tr/// 计算每个字母 MATCH 在字符串中出现的次数;在 map 的 'block' 或 'expr' 中,$_ 是一个特殊变量 - 被映射的值。] 但它获取 @allmatches 的每个元素并对其进行映射,并将其输出传递给种类。方括号形成一个数组 ref,所以输出是一个数组 refs 的数组;每个数组引用都包含单词中 MATCH 的字母数的计数,后跟单词。
那么第一行是:
print map $_->[1], ...output from sort...;
这会从排序后的输出中提取名称 $_->[1]。
- 总体而言,效果是按顺序列出
@allmatches 中的单词,使得 MATCH 中字母最少(可能为零)的单词首先出现,按字母顺序排列,其次是 MATCH 中字母最少的单词MATCH(再次按字母顺序),依此类推。
这是一个压缩的巡回演出。 如果有人将它提供给我进行审查,他们会走回绘图板。(更新:因为这是一个众所周知的习语(Schwartzian Transform),发回它的唯一原因是“布局不够仔细”和“没有注释为 Schwartzian 变换”。)
# Schwartzian Transform: sort by number of letters from MATCH and alphabetically
print map { $_->[1] }
sort { $a->[0] <=> $b->[0] or $a->[1] cmp $b->[1] }
map { [ tr/"MATCH"/"MATCH"/, $_ ] }
@allmatches;
(这正确地使用了第一项的数字比较。)
您提到对$a 和$b 感到困惑。它们基本上是魔术变量——排序中比较函数的参数。如果$a 比较小于$b,则比较必须返回负值,如果$a 比较大于$b,则返回正值,如果它们比较相等,则返回零。它们($a 和 $b)是需要两个名称时使用的名称; $_ 与 map(以及 grep 和其他列表转换函数)一起使用,只需要一个名称。