arrays - 将Perl数组排序到位

标签 arrays perl sorting

我有一个对数组的引用(称为$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/

相关文章:

python - 制作小 'Connect to a SSL webpage' 脚本的最快语言

perl - 用更时尚的东西替换我的 $i ( 0, 1, 2 )?

list - 基于第二个属性的Scala排序列表,然后是第一个

javascript - Google Apps 脚本无法为一行中的值编制索引

JavaScript 数组到 CSV

php - 将函数结果存储到变量以供以后在 PHP 中使用?

arrays - 如何将数组拆分为 n 个相等或接近相等的数组?

regex - Perl 一次完成多个模式匹配和替换

javascript - 在 AngularJS 中,如何指定二次排序?

javascript - 如何使用下划线 js 对 JavaScript 对象进行排序?