Perl: ранжировать, но не сортировать массив 1D - PullRequest
0 голосов
/ 25 октября 2018

Мне нужен код Perl для ранжирования чисел в массиве в другой массив без сортировки.Итак, input: (10, 4, 2, 9, 32) => output: (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 как одномерный массив, как описано.Желательно, если это возможно без назначения ключей для данных входного массива.

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Вот мое решение:

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
0 голосов
/ 25 октября 2018

Вы можете сделать это в два шага, сначала отсортировав индексы в массиве, затем отсортировав индексы по этим индексам, чтобы получить ранг (на основе 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;
...