Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

How to compare hash values within the same hash?

by phildeman (Sexton)
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?

  • Comment on How to compare hash values within the same hash?

Replies are listed 'Best First'.
Re: How to compare hash values within the same hash?
by choroba (Chancellor) 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 (Chancellor) 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.


    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 (Chancellor) on Sep 24, 2013 at 23:58 UTC


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

    $ cat #!/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 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.


    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 (Abbot) 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; # 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?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1055552]
Approved by ww
Front-paged by MidLifeXis
[davido]: date parsing is hard. The more examples you can provide of the input (within reason) and expected output, the better.
[stevieb]: agreed. That's why I said at least a half-dozen. If enough of the different formats are present, the date/time folk may not have to request more. If they do, then at least there was a decent base to start with
[stevieb]: I do date and time transformations in both Perl and Python, but not frequently enough to not have to search for the format params etc ;)

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2017-04-29 02:42 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (531 votes). Check out past polls.