ostra has asked for the wisdom of the Perl Monks concerning the following question:

my program inputs values from a text file and stores them in an array called @nums. Is there an alternative code that can accomplish the same task? Thank you in advance, Ostra.

#!/perl/ -w @nums=(); #array of numbers $count=0; #count of numbers while(<>){ chomp($input=$_); if($input ne ''){ $nums[$count++]=$input; } else{last;} } @nums= sort {$a<=>$b} @nums; print "\nminimum number: $nums[0]"; print "\nmaximum number: $nums[$#count]";

Replies are listed 'Best First'.
Re: storage of numbers
by Laurent_R (Canon) on Oct 16, 2013 at 17:29 UTC

    If you only need the min and the max, then you don't need to store your numbers and an array and then sort the array: just maintain a $min and $max variables as you read the file. Possibly something like this:

    my ($min, $max) = (0, 0); while(<>){ chomp($input=$_); if($input ne ''){ $min = $input if $input < $min; $max = $input if $input > $max; } else{last;} } print "Min and Max are : $min $max \n";
    EDIT: fixed a typo on the $max variable name.
      Laurent, use strict; would have caught your typo. I prefer to get the special cases out of the way early.
      use strict; use warnings; my ($min, $max) = (0, 0); while(<DATA>){ chomp( my $input = $_ ); last if $input eq ''; $min = $input if $input < $min; $max = $input if $input > $max; } print "Min and Max are : $min $max \n"; __DATA__ 11 13 56 75 53 68 89 22
      Bill

        Laurent, use strict; would have caught your typo.

        Not really, Bill, since I did not try to run or even to compile the code. In my view, this was just a small code snippet showing changes compared to the original program, not a full program. But sure, I always use strict and warnings when I write actual programs. Thanks you for mentioning the typo.

Re: storage of numbers
by davido (Cardinal) on Oct 16, 2013 at 17:42 UTC

    use Scalar::Util qw( looks_like_number ); while( <> ) { next unless looks_like_number($_); chomp; $min = ! defined( $min ) || $min > $_ ? $_ : $min; $max = ! defined( $max ) || $max < $_ ? $_ : $max; } print "\nminimum number: $min\n"; print "maximum number: $max\n";

    Dave

      Do you know that
      perl -MScalar::Util=looks_like_number -e 'print looks_like_number "Inf +"'
      prints true?

        That's not what happens under Win7, perl 5.16, and the latest AS 5.16-repository version of Scalar::Util (with quotes adjusted for MS pleasure):

        C:\>perl -MScalar::Util=looks_like_number -e "print looks_like_number +'Inf'" 20

        Oh. OK, if you say so. But why did the output ne 'True' (unless 'Inf/INF/inf' is treated as NAN?
        Just then, though, a lightbulb flashed on -- AhHA,   /me said to myself!     RTFM!

        looks_like_number EXPR Returns true if perl thinks EXPR is a number. See "looks_like_number" +in perlapi.

        Unfortunately, the link, <a href="/perldoc?perlapi#looks_like_number" class="podlinkpod">&#34;looks_like_number&#34; in perlapi</a> (to which 'See' directs us) is broken.

        So forging blindly onward with what seemed, OTTOMH, some semi-plausible alternatives:

        C:\>perl -e "use Scalar::Util(looks_like_number); print looks_like_num +ber 'Inf'" 20 C:\>perl -e "use Scalar::Util(looks_like_number); print looks_like_num +ber 'foo'" 0 C:\>perl -e "use Scalar::Util(looks_like_number); print looks_like_num +ber 'inf'" 20 C:\>perl -e "use Scalar::Util(looks_like_number); print looks_like_num +ber '7'" 1 C:\>perl -e "use Scalar::Util(looks_like_number); print looks_like_num +ber '7874321907'" 2 C:\>perl -e "use Scalar::Util(looks_like_number); print looks_like_num +ber(7874321907)" 8704

        It all leaves me deep in 'WTF' territory and slipping into the quicksand.

        So prithee, Wiser heads: Prevail! and halp, hal blubh blub o o ....

        Update: added first 1.5 sentences after the first blockquoted code.

        Do you know that...

        Yes, it's documented in perlapi. I didn't assume that would be a concern for the OP.

        The old pure-Perl version of Scalar::Util has a pure-Perl version of looks_like_number, which includes the following code:

        return 1 if ( $] >= 5.008 and /^(Inf(inity)?|NaN)$/i ) or ( $] >= 5.006001 and /^Inf$/i );

        So if we wanted to eliminate that behavior, we could either copy/paste and modify the entire pure-Perl version from an old version of Scalar::Util (but it has issues with '0 but true'), or use the modern version of Scalar::Util::looks_like_number like this:

        sub looks_like_finite_number { my $candidate = shift; return 0 if ! looks_like_number( $candidate ); return 0 if ( $] >= 5.008 and $candidate =~ /^(Inf(inity)?|NaN)$/i) or ( $] >= 5.006001 and $candidate =~ /^Inf$/i ); return 1; }

        Or, in perlfaq4 there is a series of regexes given for determining if one is looking at a number under the section, "How do I determine whether a scalar is a number/whole/integer/float? It's not pretty, and that FAQ answer has even changed over the years; it used to use a bunch of "if" statements. Now it uses given/when. *sigh*


        Dave

Re: storage of numbers
by GotToBTru (Prior) on Oct 16, 2013 at 20:20 UTC
    Simplified array insert, in case you do need the list for later processing. Also corrected typo in last statement (and updated to fix my own to end on null input).
    #!/perl/ -w use strict; my (@nums,$input); #array of numbers while(<>){ chomp($input=$_); last if ($input eq ''); push @nums, $input; } @nums= sort {$a<=>$b} @nums; print "\nminimum number: $nums[0]"; print "\nmaximum number: $nums[$#nums]";
Re: storage of numbers
by kcott (Archbishop) on Oct 17, 2013 at 07:16 UTC

    G'day Ostra,

    "my program inputs values from a text file and stores them in an array called @nums. Is there an alternative code that can accomplish the same task?"

    Tie::File does exactly that, e.g.

    tie my @nums, 'Tie::File', $filename;

    List::Util has functions to find the minimum and maximum values:

    min(@nums); max(@nums);

    Given this file:

    $ cat pm_num_list.txt 123 12e3 12e-3 -12e3 -123

    This code:

    #!/usr/bin/env perl use strict; use warnings; use autodie; use List::Util qw{min max}; use Tie::File; tie my @nums, 'Tie::File', 'pm_num_list.txt'; print 'Min: ', min(@nums), "\n"; print 'Max: ', max(@nums), "\n"; untie @nums;

    Produces this output:

    Min: -12e3 Max: 12e3

    You've been shown a few alternative methods for achieving this task. If efficiency is of concern to you, use Benchmark to compare them.

    Here's links to the three pragmata I used: strict, warnings and autodie. strict and warnings are recommended for all your programs; autodie for code involving I/O (and a few other cases: check the doco).

    -- Ken