I need to find the max value of all values in a Perl hash. I don't need the key, just the highest value, so that I can increase it and return a new value that is higher than before. Simplest thing in the world. I took inspiration from this answer: https://stackoverflow.com/a/2891180/2740187, and implemented this piece of code:
use List::Util qw( reduce min max );
my %gid = ("abc" => 1, "def" => 1);
my $gid_ref = \%gid;
my $max_gid = reduce { $a > $b ? $a : $b } values %$gid_ref || 0;
print "$max_gid\n";
As you can see, the hash only contains two 1's as values. Then why is it printing "2"? At least it does on my machine.
I guess I just could write
my $max2 = max(values %$gid_ref) || 0;
to get the max value anyway, but I really would like to understand what is happening here.
You can also use lower precedence or
operator instead of ||
, which doesn't impose scalar context on values()
my $max_gid = (reduce { $a > $b ? $a : $b } values %$gid_ref or 0);
(parentheses are mandatory here and warnings will complain if you omit them)
This line
my $max_gid = reduce { $a > $b ? $a : $b } values %$gid_ref || 0;
is parsed as
my $max_gid = reduce { $a > $b ? $a : $b } (values %$gid_ref || 0);
and
(values %$gid_ref || 0)
is using values
in scalar context, which evaluates to the number of elements in the hash (2). Since 2 || 0
is still 2
, you perform your reduction on a scalar and get back the value.
On the other hand
my $max_gid = (reduce { $a > $b ? $a : $b } values %$gid_ref) || 0;
does get the maximum of the sequence as intended.
What's the purpose of the || 0
anyway? The documentation recommends
If your algorithm requires that reduce produce an identity value, then make sure that you always pass that identity value as the first argument to prevent undef being returned.
So you probably want
my $max_gid = reduce { $a > $b ? $a : $b } 0, values %$gid_ref;
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