Perl:有人可以解释这段代码吗?它涉及map,sort,tr和references.(改进的Schwartzian变换)

Jon*_*Jon 3 perl

我已经在地图,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; 
Run Code Online (Sandbox Code Playgroud)

所以我特别需要的是:$ _指的是什么(未定义?)

包括地图在内的最后一行做了什么?

我还不太了解$ a和$ b概念.他们指的是什么?@allmatches的第一个和下一个元素?

另外,所有逗号(在地图之后)做什么?如果这就像Schwartzian变换那么好,因为我还不明白,尽管阅读.

这是我的想法:将
未定义的标量映射为数组的引用(哪个?)同时调用第二个元素:[1].它首先根据"MATCH"的出现次数排序我的@allmatches数组,然后按字母表排序.通过参考的第二张地图对我来说很粗糙(地图在一步中做了很多); tr返回次数.第二个"MATCH"没用,但为什么呢?

额外奖励:有什么可以替换tr ///来排序更多,比如这是否可能:tr/MATCH#\ d + // ??

Nem*_*emo 14

从右到左阅读(即,按顺序执行)......

map [ tr/"MATCH"/"MATCH"/, $_ ], @allmatches;
Run Code Online (Sandbox Code Playgroud)

对于@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变换.]

  • 解释是正确的,但你还应该提到这个成语(`map sort map`)被称为[Schwartzian变换](http://en.wikipedia.org/wiki/Schwartzian_transform),用于有效地排序数组由一个可能很昂贵的密钥来计算. (4认同)
  • +1解释.我觉得你是对的; 这是一个错误.`cmp`将整数值转换为字符串,因此当'10 <=> 2`返回`1`时,`10 cmp 2`返回`-1`(因为'10'lt'2'). (2认同)

tch*_*ist 10

不要从右到左阅读; 格式化它更好(原版是残酷的),然后从下到上阅读:

print map  { $_->[1] }
      sort {
              $b->[0] <=> $a->[0]
                      ||
              $a->[1] cmp $b->[1]
           }
      map  { [ tr/MATCH// => $_ ] }
      @allmatches;
Run Code Online (Sandbox Code Playgroud)

或者使用更灵活的哈希代替:

print map  { $_->{DATA} }
      sort {
              $b->{COUNT} <=> $a->{COUNT}
                          ||
              $a->{DATA}  cmp $b->{DATA}
           }
      map  {
             +{
                COUNT  => tr/MATCH//,
                DATA   => $_,
              }
      } @allmatches;
Run Code Online (Sandbox Code Playgroud)

这当然与此相同:

print map  {         $$_{DATA}      }
      sort {
              $$b{COUNT} <=> $$a{COUNT}
                          ||
              $$a{DATA}  cmp $$b{DATA}
           }
      map  {
             +{
                  COUNT  => tr/MATCH//,
                  DATA   => $_,
              }
      } @allmatches;
Run Code Online (Sandbox Code Playgroud)

看看它有多好?另外,当您从下到上阅读它时,它对应于一个完全直截了当的shell风格的数据流:

  map @allmatches | sort | map | print
Run Code Online (Sandbox Code Playgroud)

这比理解起来容易得多

  print(map(sort(map @allmatches)))
Run Code Online (Sandbox Code Playgroud)

这就是为什么每个人都喜欢shell的数据流模型的原因.