问题描述
我有一个对数组的引用(称为 $ intervals
),我想对该数组中的值进行排序.数组中可能有很多值,所以我宁愿不要复制这些值.我目前的做法是这样.
I have a reference to an array (called $intervals
) and I would like to sort the values in this array. It's possible that there could be a huge number of values in the array, so I would prefer not to copy the values. My current approach is this.
sub by_position
{
$a->start <=> $b->start ||
$a->end <=> $b->end
}
my @sorted_intervals = sort by_position (@$intervals);
但是,如果我对Perl的理解正确,那的确会复制数组中的所有值.是对的吗?如果是这样,是否有一种方法可以对数组进行就地排序(使用对该数组的引用)?
However, if I understand Perl correctly this will indeed copy all of the values in the array. Is that right? If so, is there a way that I can do an in-place sort of an array (using a reference to that array)?
推荐答案
Perl允许使用成语 @arr = sort @arr
就地对数组进行排序.与赋值运算符的正常行为相反,在这种情况下不会进行任何复制.但是,此优化仅限于常规数组变量;它不适用于数组引用:
Perl allows arrays to be sorted in-place with the idiom @arr = sort @arr
. Contrary to the normal behavior of the assignment operator, no copies will be made in this case. However, this optimization is limited to normal array variables; it won't work with array references:
让我们使用 -MO = Concise
选项进行深入了解.首先,我们进行常规的原位排序以查看期望的结果:
Let's look under the hood by using the -MO=Concise
option. First, we do normal in-place sorting to see what we'd expect:
$ 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
,似乎已就位.现在,让我们用引用做同样的事情:
Interesting: <@> sort lK/INPLACE ->8
, which seems to sort in place. Now let's do the same thing with references:
$ 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
我在< @>中看不到就位标记排序lK-> a
.因此,优化似乎仅在使用相同的变量时有效,而在使用相同的数组时则无效.但这意味着,如果我们将数组变量别名为某个标量引用的数组,则可以对数组引用进行排序(使用数据::别名):
I do not see an inplace flag in <@> sort lK ->a
. So the optimization only seems to work when using the same variable, not when using the same array. But this means we can sort array references in place if we alias an array variable to the array referenced by some scalar (using 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标记再次出现在< @>中.排序lK/INPLACE-> e
:-)
… and the inplace-flag is there again <@> sort lK/INPLACE ->e
:-)
这意味着 Eric Strom的答案不正确.
这篇关于将Perl数组排序到位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!