Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this reduce {} not returning the max value as expected?

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.

like image 393
jackthehipster Avatar asked Dec 24 '22 23:12

jackthehipster


2 Answers

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)

like image 40
mpapec Avatar answered Jan 04 '23 23:01

mpapec


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;
like image 185
Ben Voigt Avatar answered Jan 04 '23 22:01

Ben Voigt