in reply to minimum, maximum and average of a list of numbers at the same time

As others have mentioned, you are unlikely to code anything in Perl that will beat List::Util for performance, even if you do avoid making 3 whole passes. That is the nature of a dynamic language.

For error handling, you need to add code to detect and deal with them. You have to decide whether to die or croak within the subroutine, or return some failure indication (like an empty list).

Here's one possibility that raises an exception (via die) within the sub and catches it in the calling code using the block form of eval:

#! perl -slw use strict; sub minMaxAve { die 'Empty list' unless @_; my( $min, $max, $sum ); for( @_ ) { die 'Non-numeric value(s)' unless /^[\de+.-]+$/; $min = $_ if !defined $min or $min > $_; $max = $_ if !defined $max or $max < $_; $sum += $_; } return $min, $max, $sum / @_; } for ( [], [ 1 .. 4 ], [ 5 , 1, 5, 6, 5 ], [ 1, 2, -0.1, 1e-5, 2e10 ], [ 'fox', 'dog' ] ) { my @results = eval{ minMaxAve @$_ } or warn "[ @$_ ] : $@\n\n" and + next; printf "[ %s ]\nmin: %g max: %g ave: %g\n\n", join( ', ',@$_ ), @r +esults; } __END__ P:\test>junk2 [ ] : Empty list at P:\test\junk2.pl line 5. [ 1, 2, 3, 4 ] min: 1 max: 4 ave: 2.5 [ 5, 1, 5, 6, 5 ] min: 1 max: 6 ave: 4.4 [ 1, 2, -0.1, 1e-005, 20000000000 ] min: -0.1 max: 2e+010 ave: 4e+009 [ fox dog ] : Non-numeric value(s) at P:\test\junk2.pl line 8.

You should probably use Carp::croak rather than die, a better regex (say from Regexp::Common) or better, Scalar::Util::looks_like_number() to detect non-numeric values.

And, if performance is your requirement, List::Util's calls, but make sure that you get a version that compiles the XS alternatives on your platform.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
  • Comment on Re: minimum, maximum and average of a list of numbers at the same time
  • Download Code

Replies are listed 'Best First'.
Re^2: minimum, maximum and average of a list of numbers at the same time
by polettix (Vicar) on Nov 10, 2005 at 15:46 UTC
    I would also add List::Moreutils, which has a minmax function using an improved algorithm to evaluate min and max at once:
    #!/usr/bin/perl use strict; use warnings; use List::Util qw( min max reduce ); use List::MoreUtils qw( minmax ); use Benchmark qw( cmpthese ); my @array = map { rand 100 } 1 .. 1_000_000; my $count = 0; cmpthese -10, { util_min_max => sub { my $min = min(@array); my $max = max(@array); }, util_reduce => sub { my ( $min, $max ) = @{ (reduce { my $r= ref $a ? $a : [($a) x 2]; if ($b < $r->[0]) { $r->[0]= $b; } elsif ($b > $r->[1]) { $r->[1]= $b; } $r } @array) }; }, moreutils_minmax => sub { my ( $min, $max ) = minmax(@array); }, }; __END__ Rate util_reduce util_min_max moreutils_m +inmax util_reduce 0.846/s -- -92% + -96% util_min_max 10.5/s 1146% -- + -45% moreutils_minmax 19.2/s 2169% 82% + --
    I added the reduce method because I did not know if it would perform better, but the result does not surprise me given the bunch of function calls that are involved. Anyway, this is what benchmarks are for :)

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.