我有以下代码,在排序比较器中,它在进行比较之前删除了前缀字符串.
print for sort {
$a =~ s/^STRING//;
$b =~ s/^STRING//;
foo($a) cmp foo($b)
} @a;
Run Code Online (Sandbox Code Playgroud)
虽然比较和顺序是正确的,但是从输出中删除了前缀字符串.
以下保留前缀字符串(如我所愿).
print for sort {
$x = a;
$y = b;
$x =~ s/^STRING//;
$y =~ s/^STRING//;
foo($x) cmp foo($y)
} @a;
Run Code Online (Sandbox Code Playgroud)
但我很困惑第二部分如何保留前缀.
它是否正在执行字符串的副本,并且在数组的情况下剥离原始引用?
我也是在第一个片段中做错了什么并最终解决了这个问题?
一种方法:使用/r
修饰符
print for sort {
foo( $a =~ s/^STRING//r ) cmp foo( $b =~ s/^STRING//r )
} @ary
Run Code Online (Sandbox Code Playgroud)
替换运算符s/
返回修改后的字符串并保持原始状态不变.如果没有匹配,则返回原始字符串,这似乎符合目的.如果在大型数组上使用,或者函数调用需要时间,请参见最后的优化.
另一种方法是在可行时将替换更改为匹配和捕获.
还有就是这了广泛的讨论排序.首先,$a
和$b
是(包)全局
的
$a
和$b
在包的排序()是从被称为设置为包全局
该块{ }
代表一个匿名子程序和
......要比较的元素被传递到子程序作为包全局变量
$a
和$b
所以别名意味着改变它们会影响元素.从而
要比较的值始终通过引用传递,不应修改.
当什么发生$a
,$b
得到改变这样的元素发生变化.
在第二种情况下,你复制$a
并$b
进入(应该是什么!)词法$x
,$y
并且与之连接@ary
被破坏,因此元素不会被更改.
请始终拥有use warnings;
并use strict;
在计划的开头.这是一个非常好的,如果是极端的例子 - 你介绍的用于尝试的变量是全局($x
)还是词法(my $x
)可能很重要.
处理元素以使用结果值进行排序比较的代码存在效率缺陷.比较一次在两个元素上完成,因此元素被多次处理.每次我们进行相同的处理并为元素计算相同的值.
这种低效率仅适用于足够大的数据集,并且大部分时间都不用担心.但在这种情况下,正则表达式引擎运行并且还涉及函数调用,并且这些在Perl中并不完全便宜.此外,调用的开销未指定,我想有一些工作涉及.
为了优化这个,可以预处理输入然后排序
my @sorted_ary =
map { $_->[1] }
sort { $a->[0] cmp $b->[0] }
map { [ foo( s/^STRING//r ), $_ ] }
@ary;
Run Code Online (Sandbox Code Playgroud)
的map
,是以输入@ary
应用正则表达式和函数调用并存储结果,与原来的元件沿,在两元件数组引用,对于中的每个元素@ary
.然后sort
使用第一个arrayref元素对该arrayrefs列表进行编辑以进行比较.最后一个map
从排序的arrayrefs中提取第二个元素,从而返回根据需要排序的原始项目.
这称为Schwartzian变换.例如,请参阅sort中的 " 示例 " .
应该记住,只有足够大的数据才能获得增益,而这种机动也带来了开销(并且在更复杂的代码中).因此,只有在存在可分类的问题时才考虑使用它.