Return all hash key / value pairs with maximum value

I have a hash (in Perl) where the values ​​are all numbers. I need to create another hash containing all key / value pairs from the first hash, where the value is the maximum for all values.

For example, given

my %hash = (
    key1 => 2,
    key2 => 6,
    key3 => 6,
);

I would like to create a new hash containing:

%hash_max = (
    key2 => 6,
    key3 => 6,
);

I'm sure there are many ways to do this, but I'm looking for an elegant solution (and the opportunity to learn!).

+3
source share
3 answers
use List::Util 'max';
my $max = max(values %hash);
my %hash_max = map { $hash{$_}==$max ? ($_, $max) : () } keys %hash;

Or a single pass (similar, but slightly different from the other):

my $max;
my %hash_max;
keys %hash; # reset iterator
while (my ($key, $value) = each %hash) {
    if ( !defined $max || $value > $max ) {
        %hash_max = ();
        $max = $value;
    }
    $hash_max{$key} = $value if $max == $value;
}
+7
source

This causes data to be skipped, but spends a lot of hash entries:

use strict;
use warnings;

my %hash = (
    key1 => 2,
    key2 => 6,
    key3 => 6,
);

my %hash_max = ();
my $max;
foreach my $key (keys %hash) {
        if (!defined($max) || $max < $hash{$key} ) {
                %hash_max = ();
                $max = $hash{$key};
                $hash_max{$key} = $hash{$key};
        }
        elsif ($max == $hash{$key}) {
                $hash_max{$key} = $hash{$key};
        }
}

foreach my $key (keys %hash_max) {
        print "$key\t$hash_max{$key}\n";
}
+1
source
# sort numerically descending
my @topkey = sort {$hash{$b} <=> $hash{$a}} keys %hash;

% hash_max, :

for $key (@topkey) {
    if ($hash{$key} == $hash{$topkey[0]}) {
        $hash_max{$key} = $hash{$key}
    } else { last }
}

ETA: , last , @topkey , , . .

+1
source

All Articles