Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

How to compare hash values within the same hash?

by phildeman (Acolyte)
on Sep 24, 2013 at 22:24 UTC ( #1055552=perlquestion: print w/ replies, xml ) Need Help??
phildeman has asked for the wisdom of the Perl Monks concerning the following question:

Is there a way to compare the values of one hash (while looping through the hash) and determine how many times
a value has occurred in the hash?

$hash = (
     key1 => 10,
     key2 => 10,
     key3 => 3,
     key4 => 5,
     key5 => 10
);

In the hash, above, there are 3 occurrences of the value 10. I need to do this in order display the value
that has the highest frequency. Perhaps, there is a way to loop through the hash to compare the current
value to the previous value, then increment a counter variable by 1?

Any suggestions?

Thanks.

Comment on How to compare hash values within the same hash?
Re: How to compare hash values within the same hash?
by choroba (Abbot) on Sep 24, 2013 at 22:39 UTC
    Attention - when assigning to a hash, start its name with the percent sigil, not dollar:
    %hash = ( key1 => 10, # ... );

    To count numbers of occurrences, hashes are usually used:

    my %freq; my ($max_freq, $max_value) = 0; for my $value (values %hash) { $freq{$value}++; if ($freq{$value} > $max_freq) { $max_freq = $freq{$value}; $max_value = $value; } } print "$max_value: $max_freq times\n";
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: How to compare hash values within the same hash?
by LanX (Canon) on Sep 24, 2013 at 23:53 UTC
    DB<100> %hash = ( key1 => 10, key2 => 10, key3 => 3, key4 => 5, key5 => 10 ); => ("key1", 10, "key2", 10, "key3", 3, "key4", 5, "key5", 10) DB<101> $count{$_}++ for values %hash => "" DB<102> \%count => { 3 => 1, 5 => 1, 10 => 3 } DB<106> ($max) = reverse sort values %count => 3 DB<109> grep { $count{$_} == $max } %count => 10

    this will give you a list of all values which are maximal, not only one.

    update

    otherwise, if only one value is enough:

    DB<119> %rcount= reverse %count => (3, 10, 3, 10) DB<120> \%rcount => { 1 => 3, 3 => 10 } DB<121> $rcount{$max} => 10

    and here an easier approach to find the maxmimum.

    DB<113> use List::Util qw/max/ DB<114> $max = max values %count => 3

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: How to compare hash values within the same hash?
by roboticus (Canon) on Sep 24, 2013 at 23:58 UTC

    phildeman:

    I like to invert the hash for things like this. This way, you get a list of the keys for each value:

    $ cat t.pl #!/usr/bin/perl my %hash = (key1=>10,key2=>10,key3=>3,key4=>5,key5=>10); my %invhash; while (my ($k,$v) = each %hash) { push @{$invhash{$v}}, $k; } for my $v (sort {$a<=>$b} keys %invhash) { print "$v cnt=", scalar(@{$invhash{$v}}), " keys=",join(", ",@{$invhash{$v}}), "\n"; } $ perl t.pl 3 cnt=1 keys=key3 5 cnt=1 keys=key4 10 cnt=3 keys=key5, key2, key1

    But if you don't find the list of keys useful, or if there's too much data, just incrementing a counter as you suggest will do the job.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: How to compare hash values within the same hash?
by Anonymous Monk on Sep 25, 2013 at 03:11 UTC

    You already have good answers. TIMTOWTDI:

    # Frequency of each value. my %freq; $freq{$_}++ for values %hash; # Sort by frequency. my @bucket; @bucket[values %freq] = keys %freq; print "There are $#bucket occurrences of the value $bucket[-1].\n";
Re: How to compare hash values within the same hash?
by Marshall (Prior) on Sep 25, 2013 at 10:00 UTC
    I think you want the peg counts (3rd printout below), but I showed some other stuff just for fun.
    #!usr/bin/perl -w use strict; #http://perlmonks.org/?node_id=1055552 my %hash = ( key1 => 10, key3 => 3, key2 => 10, key4 => 5, key5 => 10, key6 => 3, ); # The keys don't matter. # What matters is the histogram of the values. my %histo; #histogram of each key's summary data my %pegs; #peg count's of each key #a bit brain boggling, but it works for a sum... #the (my $value's) are pre-computed at start of the loop # foreach my $value (values %hash) { $pegs{$value}++; $histo{$value}+=$value; } # # various print formats... # print "histo sort by key:\n"; foreach my $x (sort {$a <=> $b} keys %histo) { print "$x => $histo{$x}\n"; } print "\nhisto sort by inverse value:\n"; foreach my $x (sort {$histo{$b} <=> $histo{$a}} keys %histo) { print "$x => $histo{$x}\n"; } print "\nPeg counts of values\n"; foreach my $x (sort {$pegs{$a} <=> $pegs{$b}} keys %pegs) { print "$x => $pegs{$x}\n"; } =summary of prints: sort by key of sums: 3 => 6 #keys 3,6 5 => 5 #keys 5 10 => 30 #keys 1,2,5 sort by inverse value of sums: (note swap of $b and $a) #I did that to make it a bit more interesting... 10 => 30 3 => 6 5 => 5 Peg counts of values: (value and number of times seen) 5 => 1 3 => 2 10 => 3 =cut
    There are a number of ways to present the max (eg 10 => 3) peg count, but what do you want if say 3=>3 also?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1055552]
Approved by ww
Front-paged by MidLifeXis
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (12)
As of 2014-12-22 07:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (112 votes), past polls