我已经在地图,tr和引用上阅读了教程和perldoc,但这个代码对于像我这样的初学者Perl用户来说有点过于先进。
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;
所以我特别需要的是:$ _指的是什么(未定义?)
包括地图在内的最后一行做了什么?
我还不太了解$ a和$ b概念。他们指的是什么? @allmatches的第一个和下一个元素?
此外,所有逗号(在地图之后)做什么?如果这就像Schwartzian变换一样好,因为我还不明白,尽管阅读。
这是我的想法:
将未定义的标量映射为对数组的引用(?)同时调用第二个元素:[1]。它首先根据“MATCH”的出现次数然后按字母表排序我的@allmatches数组。通过参考的第二张地图对我来说很粗糙(地图在一步中做了很多); tr返回次数。第二个“MATCH”没用,但为什么呢?
奖励:我可以用什么替换tr ///来进行更多排序,如果可能的话:tr / MATCH#\ d + // ??
答案 0 :(得分:14)
从右向左阅读(即按执行顺序)......
map [ tr/"MATCH"/"MATCH"/, $_ ], @allmatches;
对于@allmatches的每个元素e,这将创建对双元素数组的引用,其第一个元素是数字,第二个元素是e。地图的结果是这些参考的数组。
tr/"MATCH"/"MATCH"/
计算字母M,A,T,C或H出现在e中的次数。 (技术上用M代替M,用A代替A,用T代替T等,并计算它做了多少这样的替换。)
实际上,它也在计算引号字符,因为tr ///将处理与其他任何内容相同的字符。这似乎是一个错误。
无论如何,让我们说这些引用中的每一个引用一个数组[n,e],其中n是奇怪的数,e是@allmatches的原始元素。
然后“sort”对引用数组进行排序,主要由n(解释为字符串,而不是数字;这似乎是另一个错误),其次是字符串e。
最后,最外面的“map”在排序完成后从每个双元素数组中提取第二个元素(e)。所以最终的结果就是对@allmatches的元素做一个奇怪的(我相信,错误的)排序。
[编辑:正如cjm在评论中指出的那样,此map sort map
成语称为Schwartzian transform。]
答案 1 :(得分:10)
不要从右到左阅读;格式化得更好(原版是残酷的),然后从下到上阅读:
print map { $_->[1] }
sort {
$b->[0] <=> $a->[0]
||
$a->[1] cmp $b->[1]
}
map { [ tr/MATCH// => $_ ] }
@allmatches;
或者使用更灵活的哈希值:
print map { $_->{DATA} }
sort {
$b->{COUNT} <=> $a->{COUNT}
||
$a->{DATA} cmp $b->{DATA}
}
map {
+{
COUNT => tr/MATCH//,
DATA => $_,
}
} @allmatches;
这当然与此相同:
print map { $$_{DATA} }
sort {
$$b{COUNT} <=> $$a{COUNT}
||
$$a{DATA} cmp $$b{DATA}
}
map {
+{
COUNT => tr/MATCH//,
DATA => $_,
}
} @allmatches;
看看它有多好?另外,当你从头到尾阅读它时,它对应于一个完全直截了当的shell风格的数据流:
map @allmatches | sort | map | print
比
更容易理解 print(map(sort(map @allmatches)))
并且是每个人都喜欢shell的数据流模型的原因。
答案 2 :(得分:3)
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...
数组的每个元素本身都是一个数组引用,并且比较执行数组引用的第一个元素的字符串比较(cmp
),如果它们相等(cmp
返回0 ),第二个元素。
因此,输出是一个排序数组。这留下了两块代码来剖析。第一行和最后一行。最后一行运行map
:
map [ tr/"MATCH"/"MATCH"/, $_ ], @allmatches
由于tr///
运算符中的左右字符串相同,因此显然执行无操作转换;这有点令人费解。 [更新:tr///
计算每个字母MATCH出现在字符串中的次数;在map
的'block'或'expr'中,$_
是一个特殊变量 - 被映射的值。]但它需要@allmatches
的每个元素并映射它,并输出将其传递给排序。方括号形成一个数组ref,因此输出是一个数组引用数组;每个数组引用都包含单词中MATCH的字母数,后跟单词。
第一行是:
print map $_->[1], ...output from sort...;
这将从已排序的输出中提取名称$_->[1]
。
@allmatches
中的单词,使得来自MATCH的字母数量最少(可能为零)的字母按字母顺序排在第一位,然后是下一个最少的字母。来自MATCH的字母(再次按字母顺序排列),等等。压缩中的巡回演出。 如果有人提供给我审查,他们会回到绘图板。(更新:因为这是一个已知的习语(Schwartzian Transform ),发送回来的唯一原因是“没有足够仔细地布置”和“没有注释为施瓦兹变换”。)
# 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
和其他列表转换函数)一起使用,其中只需要一个名称。