简体   繁体   English

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

[英]Perl: Rank but don't sort 1D array

I need Perl code to rank numbers in an array into another array without sorting it. 我需要Perl代码来将一个数组中的数字排列到另一个数组中而不对其进行排序。 So, input: (10, 4, 2, 9, 32) => output: (4, 2, 1, 3, 5) 因此,输入:(10,4,2,9,32)=>输出:(4,2,1,3,5)

I have this code that is close but I find it useless because input and output is not exactly what I want: 我的代码很接近,但是我发现它没用,因为输入和输出不完全是我想要的:

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;

The above code outputs: 上面的代码输出:

3 2 4 1 5

The output is wrong and output at all is by the way not neccessary, I just want my result array @rank as a 1D array as described. 输出是错误的,并且根本不需要输出,我只希望将我的结果数组@rank设置为如上所述的一维数组。 Preferably if it's possible without assigning the keys to the input array data. 最好在不将键分配给输入数组数据的情况下。

Here's my solution: 这是我的解决方案:

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";

We construct a hash that maps each number to its corresponding rank, then print the rank of each number in the order of the original array. 我们构造一个散列,将每个数字映射到其对应的等级,然后按照原始数组的顺序打印每个数字的等级。

We compute the rank by pairing up each number (in sorted order) with the list 1, 2, 3, ..., that is: 我们通过将每个数字(按排序顺序)与列表1、2、3,...配对来计算等级,即:

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

You can do this in two steps, first sorting the indexes to the array, then sorting indexes to those indexes to get the (0-based) rank, adding one to get a 1-based 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;

Alternatively, the following might be a tad faster (though it probably only matters for really long lists). 另外,以下方法可能会更快一些(尽管这可能仅对很长的列表才有意义)。

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM