Perl:排名,但不对一维数组排序

时间:2018-10-25 18:50:03

标签: arrays perl rank

我需要Perl代码来将一个数组中的数字排列到另一个数组中而不对其进行排序。因此,输入:(10,4,2,9,32)=>输出:(4,2,1,3,5)

我的代码很接近,但是我发现它没用,因为输入和输出不完全是我想要的:

use strict;
use warnings;
use Data::Dumper;

my %data = 
(
  1 => 10,
  2 => 4,
  3 => 2,
  4 => 9,
  5 => 32,
);

my ($n, @rank) = 1;
foreach( keys %data){
    $rank[ $data{$_} ] .= "$_ ";
}

defined and $n += print for @rank;

上面的代码输出:

3 2 4 1 5

输出是错误的,顺便说一句,输出根本不是必需的,我只希望将结果数组@rank用作所述的1D数组。最好在不将键分配给输入数组数据的情况下。

2 个答案:

答案 0 :(得分:3)

这是我的解决方法:

use strict;
use warnings;

my @numbers = (10, 4, 2, 9, 32);

my %rank_of;
@rank_of{sort { $a <=> $b } @numbers} = 1 .. @numbers;

print join(" ", map $rank_of{$_}, @numbers), "\n";

我们构造了一个散列,将每个数字映射到其对应的等级,然后按照原始数组的顺序打印每个数字的等级。

我们通过将每个数字(按排序顺序)与列表1、2、3,...配对来计算等级,即:

2 4 9 10 32   # sort { $a <=> $b } @numbers
| | |  |  |
1 2 3  4  5   # 1 .. @numbers

答案 1 :(得分:1)

您可以分两步执行此操作,首先对数组的索引排序,然后对这些索引的索引排序以获得(从0开始)排名,再加一个以获得从1开始的排名。

my @array = (10, 4, 2, 9, 32);

my @index_by_rank_minus_1 = sort { $array[$a] <=> $array[$b] } 0..$#array;
my @ranks =
    map $_+1,
    sort { $index_by_rank_minus_1[$a] <=> $index_by_rank_minus_1[$b] } 0..$#array;

或者,以下内容可能会更快一些(尽管它可能仅对很长的列表才有意义)。

my @array = (10, 4, 2, 9, 32);

my %rank_by_index;
@rank_by_index{ sort { $array[$a] <=> $array[$b] } 0..$#array } = 1..@array;
my @ranks = map { $rank_by_index{$_} } 0..$#array;