简体   繁体   中英

Perl: Rank but don't sort 1D array

I need Perl code to rank numbers in an array into another array without sorting it. So, input: (10, 4, 2, 9, 32) => output: (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. 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:

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.

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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