Perl: сортировка значений хэша и помещение результата в новый хеш, где ключи расположены в ранжировании.

У меня есть следующая структура, %hash:

$VAR1 = {
           1 => 5,
           3 => 1,
           2 => 4,
           4 => 9,

        };

Ключи этого хеша представляют собой идентификатор, а значения представляют собой номер доступа: id => номер доступа.

Я хочу отсортировать это по номеру доступа в порядке убывания и сохранить в другом хэше. Но я хочу, чтобы на этот раз значения были идентификатором. Ключами должны быть позиции в рейтинге: позиция в рейтинге (от 1 до n) => id

В этом конкретном случае:

$VAR2 = {
           1 => 4,
           2 => 1,
           3 => 2,
           4 => 3,
        };

Как мне это сделать?


person ado    schedule 31.05.2013    source источник


Ответы (3)


Вы можете использовать сортировку в цикле foreach.

my %hash = (
1 => 5,
3 => 1,
2 => 4,
4 => 9,
);

my %hash2;
my $count = 1;
foreach my $key(sort{$hash{$b} <=> $hash{$a}} keys %hash){
    $hash2{$count++} = $key;
}

use Data::Dumper;
print Dumper(\%hash2);

OR

Вы можете использовать карту для зацикливания, как упомянул Дэвид. Я добавил foreach для простоты.

my %hash2 = map {$count++ => $_} sort{$hash{$b} <=> $hash{$a}} keys %hash;
person Jithin    schedule 31.05.2013

Следующий код сортирует ключи (идентификаторы) на основе их соответствующих значений, а затем сопоставляет эти ключи с ранжированием.

use Data::Dumper;

my %old_hash = (
  1 => 5,
  3 => 1,
  2 => 4,
  4 => 9,
);

my $rank = 1;

my %new_hash
  = map  { $rank++ => $_ }
    sort { $old_hash{$b} <=> $old_hash{$a} }
    keys %old_hash;

print Dumper \%new_hash;

Это проще всего понять, если вы прочитаете конструкцию map/sort/keys задом наперед:

Во-первых, перечислите все ключи, во-вторых, отсортируйте их по значениям, которые они индексируют, в-третьих, сопоставьте новый хеш, где ключи — это текущий ранг, а значения — это связанный идентификатор.

person DavidO    schedule 31.05.2013

Вы хотите отсортировать идентификаторы, поэтому это будет выглядеть следующим образом:

my @ids_by_desc_access =
   sort { ... }
      keys(%accesses_by_id);

Вы хотите, чтобы они были отсортированы по убыванию количества доступов, поэтому мы добавляем это сравнение:

my @ids_by_desc_access =
   sort { $accesses_by_id{$b} <=> $accesses_by_id{$a} }
      keys(%accesses_by_id);

Наконец, вы, как ни странно, хотите использовать хеш в качестве массива.

my %ids_by_desc_access =
   map { $_+1 => $ids_by_desc_access[$_] }
      0..$#ids_by_desc_access;
person ikegami    schedule 31.05.2013
comment
Я напечатал это сразу после публикации вопроса, задолго до первого ответа, но потом у меня сломался компьютер. Поскольку это хороший ответ, я решил, что все равно опубликую его. - person ikegami; 31.05.2013
comment
или просто my %ids_by_desc_access; @ids_by_desc_access{1..keys %access_by_id} = sort { $access_by_id{$b} <=> $access_by_id{$a} } keys %access_by_id; - person ysth; 01.06.2013
comment
@ysth, это можно сделать в одну строку, но я учил процессу поиска ответа, а не просто даю ответ. Но спасибо за код. - person ikegami; 01.06.2013