施瓦茨变换

这可能是使用 Perl 的函数式编程工具进行排序优化的最着名的例子,用于项目的排序顺序取决于昂贵的功能。

# What you would usually do
@sorted = sort { slow($a) <=> slow($b) } @list;

# What you do to make it faster
@sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, slow($_) ] }
@list;

第一个例子的问题是比较器经常被调用并且一直使用慢速函数重新计算值。一个典型的例子是按文件大小排序文件名:

use File::stat;
@sorted = sort { stat($a)->size <=> stat($b)->size } glob "*";

这样可以工作,但最多只会产生两次系统调用的开销,最坏的情况是它必须转到磁盘,两次,每次比较,并且该磁盘可能位于另一侧的重载文件服务器中。行星。

进入 Randall Schwartz 的伎俩。

Schwartzian 变换基本上推动了 @list 的三个功能,从底部到顶部。第一个 map 将每个条目转换为原始项目的双元素列表,将慢函数的结果作为排序键,因此在结尾处我们为每个元素调用了 slow() 一次。然后,以下 sort 可以通过查看列表来简单地访问排序键。由于我们不关心排序键但只需要排序顺序的原始元素,最终的 map 会从 @sort 收到的已经排序的列表中丢弃两个元素列表,并返回仅包含其第一个成员的列表。