我有一个数组的引用(称为$间隔),我想排序这个数组中的值。在数组中可能会有大量的值,所以我不想复制这些值。我目前的做法是这样的。
sub by_position { $a->start <=> $b->start || $a->end <=> $b->end } my @sorted_intervals = sort by_position (@$intervals);
但是,如果我正确理解Perl,这将确实会复制数组中的所有值。是对的吗?如果是这样,有没有办法可以做一个数组的就地排序(使用该数组的引用)?
解决方法
Perl允许使用idiom @arr = sort @arr在原位进行数组排序。与分配运算符的正常行为相反,在这种情况下不会复制。然而,这种优化仅限于正常的数组变量;它将不适用于数组引用:
我们来看一下使用-MO = Concise选项。首先,我们做正常的就地排序,看看我们期望的:
$ perl -E'say $^V' v5.18.2 $ perl -MO=Concise -e'my @arr; @arr = sort @arr' 8 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 3 <0> padav[@arr:1,2] vM/LVINTRO ->4 4 <;> nextstate(main 2 -e:1) v:{ ->5 - <1> ex-aassign vKS/64 ->8 - <1> ex-list lK ->- 5 <0> pushmark s ->6 7 <@> sort lK/INPLACE ->8 6 <0> padrange[@arr:1,2] l/1 ->7 - <0> padav[@arr:1,2] lRM* ->7 - <1> ex-list lK ->- - <0> ex-pushmark s ->- - <0> ex-padav lRM* ->- -e Syntax OK
有趣的是:< @>排序lK / INPLACE – > 8,这似乎排序到位。现在我们来做同样的事情参考:
$ perl -MO=Concise -e'my $ref; @$ref = sort @$ref' e <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 3 <0> padsv[$ref:1,2] vM/LVINTRO ->4 4 <;> nextstate(main 2 -e:1) v:{ ->5 d <2> aassign[t4] vKS/COMMON ->e - <1> ex-list lK ->a 5 <0> pushmark s ->6 9 <@> sort lK ->a 6 <0> pushmark s ->7 8 <1> rv2av[t3] lK/1 ->9 7 <0> padsv[$ref:1,2] s ->8 - <1> ex-list lK ->d a <0> pushmark s ->b c <1> rv2av[t2] lKRM*/1 ->d b <0> padsv[$ref:1,2] sM/DREFAV ->c -e Syntax OK
我在< @>中看不到inplace标志排序lK – > a。所以优化只是在使用相同的变量时才起作用,而不是使用相同的数组时。但是这意味着如果我们将数组变量与某个标量引用的数组(使用Data::Alias)进行比较,我们可以对数组引用进行排序:
perl -MData::Alias -MO=Concise -e'my $ref; alias my @arr = @$ref; @arr = sort @arr' e <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 3 <0> padsv[$ref:1,3] vM/LVINTRO ->4 4 <;> nextstate(main 2 -e:1) v:{ ->5 - <1> entersub vKS/INARGS ->a ... a <;> nextstate(main 3 -e:1) v:{ ->b - <1> ex-aassign vKS/64 ->e - <1> ex-list lK ->- b <0> pushmark s ->c d <@> sort lK/INPLACE ->e c <0> padrange[@arr:2,3] l/1 ->d - <0> padav[@arr:2,3] lRM* ->d - <1> ex-list lK ->- - <0> ex-pushmark s ->- - <0> ex-padav lRM* ->- -e Syntax OK
…和inplace-flag再次出现< @>排序lK / INPLACE – > e