Каков самый простой способ получить ключ с самым высоким значением из хэша в Perl?
Каков самый простой способ получить ключ с самым высоким значением из хеша в Perl?
Ответ 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]