Perlのハッシュから最大値のキーを取得する最も簡単な方法は何ですか?
並べ替えを使用したソリューション:
_(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
イテレータがそれに続き、3分の1が離れています... sort
なぜ誰もがこれを手作業で行っているのかわかりません...
use List::Util qw( reduce );
my $max_val_key = reduce { $hash{$a} > $hash{$b} ? $a : $b } keys %hash;
以下は、ハッシュをソートする他の回答と比較して、よりスペース効率が高く、O(n log n)ではなくO(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は、最大値に対応するキーになります。
値の低いものから高いものへとソートされたキー:
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
に置き換えて味わってください。
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;
}
my $highest_val = (keys {$hash{$b} <=> $hash{$a}} keys %hash)[0];
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]
パフォーマンスが問題にならない場合は、もっと 読み書きのできるプログラミング ソリューションをお勧めします。
use List::Util qw(max);
max keys %hash;