Подтвердить что ты не робот

Каков самый простой способ получить ключ с самым высоким значением из хеша в Perl?

Каков самый простой способ получить ключ с самым высоким значением из хэша в Perl?

4b9b3361

Ответ 1

Пока решение с сортировкой:

(sort {$hash{$a} <=> $hash{$b}} keys %hash)[0]

найденный в некоторых других ответах, довольно изящный, он не работает так хорошо, как кажется. Во-первых, сортировка преобразует операцию поиска O(n) поиска в O(n log n). Во-вторых, решение сортировки имеет n log n хэш-образы. Взгляды на хеширование очень хороши для определенных операций, но при работе со всем хэшем поисковые запросы будут медленнее, чем использование each, keys или values для итерации по структуре данных. Это связано с тем, что итераторам не нужно вычислять хэши ключей, и им не нужно многократно ходить через бункеры, чтобы найти значения. И накладные расходы не постоянны, а возрастают по мере увеличения хешей.

Вот несколько более быстрых решений:

use strict;
use warnings;

my %hash = (
    small   => 1,
    medium  => 5,
    largest => 10,
    large   => 8,
    tiny    => 0.1,
);

Вот решение, использующее итератор each (операция O(1), выполненная n раз):

sub largest_value (\%) {
    my $hash = shift;
    keys %$hash;       # reset the each iterator

    my ($large_key, $large_val) = each %$hash;

    while (my ($key, $val) = each %$hash) {
        if ($val > $large_val) {
            $large_val = $val;
            $large_key = $key;
        }
    }
    $large_key
}

print largest_value %hash; # prints 'largest'

Или более быстрая версия, которая торгует память для скорости (она делает копию хэша):

sub largest_value_mem (\%) {
    my $hash   = shift;
    my ($key, @keys) = keys   %$hash;
    my ($big, @vals) = values %$hash;

    for (0 .. $#keys) {
        if ($vals[$_] > $big) {
            $big = $vals[$_];
            $key = $keys[$_];
        }
    }
    $key
}

print largest_value_mem %hash; # prints 'largest'

Вот производительность с различными размерами хэша:

10 keys:              Rate largest_with_sort largest_value largest_value_mem
largest_with_sort 111565/s                --           -8%              -13%
largest_value     121743/s                9%            --               -5%
largest_value_mem 127783/s               15%            5%                --

50 keys:             Rate  largest_with_sort largest_value largest_value_mem
largest_with_sort 24912/s                 --          -37%              -40%
largest_value     39361/s                58%            --               -6%
largest_value_mem 41810/s                68%            6%                --

100 keys:            Rate  largest_with_sort largest_value largest_value_mem
largest_with_sort  9894/s                 --          -50%              -56%
largest_value     19680/s                99%            --              -12%
largest_value_mem 22371/s               126%           14%                --

1,000 keys:         Rate   largest_with_sort largest_value largest_value_mem
largest_with_sort  668/s                  --          -69%              -71%
largest_value     2183/s                227%            --               -7%
largest_value_mem 2341/s                250%            7%                --

10,000 keys:        Rate   largest_with_sort largest_value largest_value_mem
largest_with_sort 46.5/s                  --          -79%              -81%
largest_value      216/s                365%            --              -11%
largest_value_mem  242/s                421%           12%                --

Как вы можете видеть, если память не очень важна, версия с внутренними массивами выполняется быстрее всего, за ней следует итератор each, а в третьей части... sort

Ответ 2

Не знаю, почему все это делают вручную...

use List::Util qw( reduce );
my $max_val_key = reduce { $hash{$a} > $hash{$b} ? $a : $b } keys %hash;

Ответ 3

Ниже приведено более эффективное пространство и будет выполняться в O (n) вместо O (n log n) по сравнению с другими ответами, сортирующими хэш. Он предполагает, что значения являются целыми числами больше 0, а хеш не пуст, но должен быть легко расширен для вашего случая.

my $key_for_max_value;
my $max_value = -1;
while ((my $key, my $value) = each %hash) {
  if ($value > $max_value) {
    $max_value = $value;
    $max_key = $key;
  }
}

$key_for_max_value теперь будет ключом, соответствующим наивысшему значению.

Ответ 4

Ключи отсортированы по значению, от самого низкого до самого высокого:

sort { $hash{$a} <=> $hash{$b} } keys %hash

Ключи отсортированы по значению, от самого высокого до самого низкого:

reverse sort { $hash{$a} <=> $hash{$b} } keys %hash

И первый элемент

(reverse sort { $hash{$a} <=> $hash{$b} } keys %hash)[0]

Замените космический корабль на cmp по вкусу.

Ответ 5

my ($max_key, $max_val) = each %hash or die "hash is empty";
while (my ($key, $val) = each %hash) {
  $max_key = $key, $max_val = $val if $val > $max_val;
}

Ответ 6

my $highest_val = (keys {$hash{$b} <=> $hash{$a}} keys %hash)[0];

Ответ 7

my $highest_val = (sort { $hash{$a} <=> $hash{$b} } keys %hash)[0];

скорее всего будет тем, что вы хотите.

Если у вас очень большой хэш, вы можете использовать что-то вроде преобразования Шварца:

my @array = map {[$hash{$_},$_]} keys %hash;
my $key_with_highest_value = (sort { $a->[0] <=> $b->[0] } @array)[0]->[1]