我有一个对数组的引用(称为$intervals
),我想对该数组中的值进行排序。数组中可能有很多值,所以我宁愿不要复制这些值。我当前的方法是这样。
sub by_position
{
$a->start <=> $b->start ||
$a->end <=> $b->end
}
my @sorted_intervals = sort by_position (@$intervals);
但是,如果我对Perl的理解正确,那的确会复制数组中的所有值。是对的吗?如果是这样,是否有一种方法可以对数组进行就地排序(使用对该数组的引用)?
最佳答案
Perl允许使用成语@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
有趣的是:
<@> sort 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
我没有在
<@> sort 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标志再次出现
<@> sort lK/INPLACE ->e
:-)这意味着Eric Strom's answer不正确。
关于arrays - 将Perl数组排序到位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5163064/