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

Perl: Rank but don't sort 1D array

我需要 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 是描述的一维数组。如果可以不将键分配给输入数组数据,最好是这样。

您可以分两步完成此操作,首先将索引排序到数组,然后将索引排序到这些索引以获得(基于 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;

这是我的解决方案:

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