http://qs1969.pair.com?node_id=1026317

maciej has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I've recently been learning a bit of perl and this site has been super helpful, so thanks to everyone who contributes.

Anyway, I've come across a problem I cannot seem to be able to figure out. I'm trying to find the coresponding key for the highest value of a hash.

My attempt is:

#!/usr/bin/perl use warnings; use strict; my %hash= ( '1', '8', '2', '6', '3','3' ,'4','7'); my $highest =0; while (my ($key, $value) = each %hash) { $highest=$key if ($highest < $value) ; print "$key key has a value $value \n"; } print "$highest key has the highest value\n";

and my results look like:

4 key has a value 7 1 key has a value 8 3 key has a value 3 2 key has a value 6 2 key has the highest value

Where as I am trying to get the last line to say "1 key has the highest value" since the value of "1" is "8"... Both keys 1 and 4 have a higher value than 2.

any tips are much appreciated.

Replies are listed 'Best First'.
Re: highest value in hash
by LanX (Saint) on Mar 31, 2013 at 03:35 UTC
    a maximal value can belong to more than just one key!

    DB<140> %h = map {$_ => int rand 3} "a" .."f" => ("a", 1, "b", 0, "c", 2, "d", 2, "e", 2, "f", 0) DB<141> use List::Util qw/max/ DB<142> $max = max values %h => 2 DB<143> @max_keys = grep { $h{$_} == $max } keys %h => ("e", "d", "c")

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: highest value in hash (key is not value)
by Anonymous Monk on Mar 31, 2013 at 02:27 UTC

    You have   $highest=$key if ($highest <  $value) ;

    You're storing the key, and comparing the key to the value

    But it sounds like you want to compare values, not keys

    So you need to store $highest_key and $highest_value, and compare $highest_value to $value

      Wow, I was trying to figure that out for the longest time and now that you pointed out what I was doing it's so obviouse. duh! Thanks everyone!
Re: highest value in hash
by Athanasius (Archbishop) on Mar 31, 2013 at 02:44 UTC

    Hello maciej, and welcome to the Monastery!

    Expanding on the advice from Anonymous Monk, here is one way to implement the solution:

    #! perl use warnings; use strict; my %hash = (1 => 8, 2 => 6, 3 => 3, 4 => 7); my $highest_value; my $highest_key; while (my ($key, $value) = each %hash) { print "$key key has value $value\n"; if (!defined $highest_value || $highest_value < $value) { $highest_key = $key; $highest_value = $value; } } print "The element with key $highest_key " . "has the highest value $highest_value\n" if defined $highest_key +;

    Output:

    12:36 >perl 591_SoPW.pl 4 key has value 7 1 key has value 8 3 key has value 3 2 key has value 6 The element with key 1 has the highest value 8 12:38 >

    Note that this uses < to compare values numerically. To compare the values as strings, you would need to use lt instead:

    if (!defined $highest_value || $highest_value lt $value)

    Hope that helps,

    Update: ++Anonymous Monk for the syntax below: it’s both simpler and more efficient. Confession: I had to re-read the documentation for each to verify that it Does the Right Thing here (it does). :-)

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Just say no to defined :)
      ... my( $highest_value, $highest_key ) = each %hash; while (my ($key, $value) = each %hash) ...
Re: highest value in hash
by hdb (Monsignor) on Apr 01, 2013 at 08:55 UTC

    Should performance be not your highest goal, you can sort the keys of the hash by their values in descending order and pick the first one:

    use warnings; use strict; my %hash= ( '1', '8', '2', '6', '3','3' ,'4','7'); my @keys = sort { $hash{$b} <=> $hash{$a} } keys %hash; print "Key with highest value is $keys[0].\n";
Re: highest value in hash
by nvivek (Vicar) on Apr 01, 2013 at 06:12 UTC

    Need to maintain both key and value in code to find which key has a largest value among all the key pairs in hash. Following is a one more way to achieve your requirement.

    use strict; use warnings; use Data::Dumper; # initializing hash %hash= ( '1' => '8', '2' => '6', '3' => '3', '4' => '7'); # print the structure print Dumper \%hash; # maintaining key and value of highest value in hash # 0th index => Key # 1st index => Value my @larger =(0,0); while (my ($key, $value) = each %hash) { # compares value with each value of hash # stores key and value whenever current value is greater than prev +ious value @larger=($key, $value) if ($larger[1] < $value) ; print "$key key has a value $value \n"; } # finally prints the key which has larger value + print $larger[0]. " key has the larger value\n";