0

so i have a hash of an hash that looks something like this:

my %hash = (
    'fruits' => {
        'apple'    => 34,
        'orange'   => 30,
        'pear'     => 45,
    },
    'chocolates' => {
        'snickers' => 35,
        'lindt'    => 20,
        'mars'     => 15,
    },
);

I want to access only the fruit which is max in number and chocolate which is max in number. the output should look like:

fruits: pear chocolates : snickers

foreach my $item (keys %hash){
#print "$item:\t"; # this is the object name
foreach my $iteminitem (keys %{$hash{$item}})
    {
    my $longestvalue = (sort {$a<=>$b} values %{$hash{$item}})[-1]; #this stores the longest value
     print "the chocolate/fruit corresponding to the longestvalue" ;   

     #iteminitem will be chocolate/fruit name
    }
 print "\n";
}

I know it is not difficult but I am blanking out!

Miller
  • 34,962
  • 4
  • 39
  • 60

3 Answers3

2

The following sorts the keys of each hashref by descending value, so the max is the first element returned:

my %hash = (
    chocolates => { lindt => 20, mars => 15, snickers => 35 },
    fruits     => { apple => 34, orange => 30, pear => 45 },
);

while (my ($key, $hashref) = each %hash) {
    my ($max) = sort {$hashref->{$b} <=> $hashref->{$a}} keys %$hashref;
    print "$key: $max\n";
}

Outputs:

fruits: pear
chocolates: snickers
Miller
  • 34,962
  • 4
  • 39
  • 60
  • And there were no syntax errors because the data structure is generated by previous lines of code and I typed it here! but thanks again :) – tonkscancode Jul 31 '14 at 00:02
  • Note: whenever I want to share a data structure, I use [`Data::Dump`](https://metacpan.org/pod/Data::Dump) to print it out. `dd \%hash;`. One can also use [`Data::Dumper`](http://perldoc.perl.org/Data/Dumper.html), but I prefer the format of the former. – Miller Jul 31 '14 at 00:49
0

Here is another way:

use strict;
use warnings;
use List::Util qw(max);

my %hash = (
    'fruits' => {
        'apple'    => 34,
        'orange'   => 30,
        'pear'     => 45,
    },
    "chocolates" => {
        'snickers' => 35,
        'lindt'    => 20,
        'mars'     => 15,
    },
);

for (keys %hash) {
    my $max = max values %{$hash{$_}};  # Find the max value 
    my %rev = reverse %{$hash{$_}};     # Reverse the internal hash
    print "$_: $rev{$max}\n";           # Print first key and lookup by max value
}

Output:

fruits: pear
chocolates: snickers
jaypal singh
  • 74,723
  • 23
  • 102
  • 147
0

For this you likely want List::UtilsBy:

use List::UtilsBy 'max_by';

my %hash = (
    chocolates => { lindt => 20, mars => 15, snickers => 35 },
    fruits     => { apple => 34, orange => 30, pear => 45 },
);

foreach my $key ( keys %hash ) {
    my $subhash = $hash{$key};
    my $maximal = max_by { $subhash->{$_} } keys %$subhash;
    print "$key: $maximal\n";
}

For this small example it probably doesn't matter too much, but for much larger cases, there's a big difference. This will run in O(n) time for the size of the hash, whereas the "sort and take first index" solution will take O(n log n) time, much slower, to sort the list of keys, only to then throw away all but the first result.

LeoNerd
  • 8,344
  • 1
  • 29
  • 36