在这个数组引用排完序之后,我们就可以从这个匿名数组里检索原始行了:
@sorted_lines = map {$_->[0] } @temp;
概而括之,这个 map-sort-map 技巧,就是我们通常称之为 Schwartzian 变换的东西,可以用一个语句实现:
@sorted_lines = map { $_->[0] }
sort {
@a_fields = @$a[1..$#$a];
@b_fields = @$b[1..$#$b];
$a_fields[3] <=> $b_fields[3]
||
$a_fields[0] <=> $b_fields[0]
||
$b_fields[2] <=> $b_fields[2]
...
}
map { [$_, split /:/]} @lines;
不要把 $a 和 $b 定义成词法变量(用 my)。它们都是包全局变量(如果它们可以免于 use strict 对普通全局变量的限制)。不过你的确需要保证你的排序过程是在同一个包里的,或者用调用者的包名字修饰 $a 和 $b。
我们已经说过,在 Perl 5.6 里你可以用标准的参数传递方法(以及不一样的是,用 XS 子过程做排序子过程)写排序子过程,前提是你用一个 ($$) 的原型声明了这个排序子过程。并且如果你是这么用的,那么实际上你是可以把 $a 和 $b 声明为词法变量的:
sub numerically ($$) {
my ($a, $b) = @_;
$a <=> $b;
}
将来,当完整的原型都实现了以后,你就可以只用说:
sub numerically ($a, $b) { $a <=> $b}
然后我们或多或少就能回到开始的地方。
splice ARRAY, OFFSET, LENGTH, LIST
splice ARRAY, OFFSET, LENGTH
splice ARRAY, OFFSET
splice ARRAY
这个函数从一个 ARRAY 中删除 OFFSET 和 LENGTH 指明的元素,并且,如果给出了LIST,则用LIST 的元素替换它。如果 OFFSET 是负数,那么该函数从数组的后面向前数,但如果该值会伸到数组开头的前面,那么就会抛出一个例外。在列表环境中,splice 返回从该数组中删除的元素。在标量环境中,它返回最后删除的元素,而如果没有的话返回 undef。如果新元素的数量不等于旧元素的数量,那么该数组根据需要伸缩,并且元素的位置根据衔接后的情况进行改变。如果省略了 LENGTH,那么该函数从数组里删除从 OFFSET 开始的所有东西。如果省略了 OFFSET,那么该数组在读取的时候清空。下面的等式成立(假设 $[ 为 0):
splice(@a, @a, 0, $x, $y)
splice(@a, 0, 0, $x, $y)
splice 函数还可以方便地用于切开传递给子过程的参数列表。比如,假设列表长度在列表之前传递:
sub list_eq { # 比较两个列表值
my @a = splice(@_, 0, shift);
my @b = splice(@_, 0, shift);
return 0 unless @a == @b; # 长度相同?
while(@a) {
return 0 if pop(@a) ne pop(@b);
}
return 1;
}
if (list_eq($len, @foo[1..$len], scalar(@bar), @bar)) { ... }
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-28372-10.html
这个很有感觉