I have a hash (in Perl) where the values are all numbers. I need to create another hash that contains all key/value pairs from the first hash where the value is the maximum of 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 am looking for an elegant solution (and an opportunity to learn!).
use List::Util 'max';
my $max = max(values %hash);
my %hash_max = map { $hash{$_}==$max ? ($_, $max) : () } keys %hash;
Or a one-pass approach (similar to but slightly different from another answer):
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;
}
This makes one pass over the data, but wastes a lot of hash writes:
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";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With