Use a hash of hashes, where the first level key is an hour, and the second level key is a function name. The values would then be arrayrefs containing all data points. You can then extract the min/max values. Or you could keep the current min/max values, and test against these for each new value.
To parse the input, I recommend the Text::CSV
module.
The code would look a bit like:
use List::Util qw/min max/;
my %times;
while (my ($hour, $fun, $val) = ...) {
push @{ $times{$hour}{$fun} }, $val;
}
for my $hour (sort { $a <=> $b } keys %times) {
my $funs = $times{$hour};
for my $fun (sort keys %$funs) {
my $vals = $funs->{$fun};
my $count = @$vals;
my $min = min @$vals;
my $max = max @$vals;
...;
}
}