Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: resetting a foreach loop!

by pryrt (Abbot)
on Nov 17, 2017 at 14:43 UTC ( [id://1203671]=note: print w/replies, xml ) Need Help??


in reply to resetting a foreach loop!

By the way, I noticed a couple more things:

  • Use lexical filehandles: open my $fh, ... instead of open FH, ...
  • Check for errors: open my $fh, ...   or die "...$!", or use autodie at the beginning of your script
  • You had a direct call to average(@array) in the print, and another call with the same data when assigning to the variable $average = average(@array); no need to average the same data twice.

To bring all the excellent suggestions to date into one post, plus these new suggestions, here is an annotated version of the updated code (note I changed to c:\temp\tsukk instead of c:\users\tsukk)

use strict; use diagnostics; use warnings; while (1) { print "Enter an input file name: "; chomp (my $choice = <STDIN>); open (my $fh, '<', "C:/temp/tsukk/$choice") # + [pryrt] use lexical filehandles or die "error opening $choice: $!"; # + [pryrt] check for errors; if you don't want this, "use autodie;" ab +ove # my @array; while (my $data = <$fh>) { push @array, $data; } # + [AnomalousMonk]'s [id://1203631] 'better yet': bring my @array into + the while(1)... my @array = <$fh>; # + [AnomalousMonk]'s [id://1203631] 'simply': slurp the whole file by +giving <> list context my $use_brostad = 1; # + set to 1 to use [brostad]'s, else false to use the anonymous sugges +tion my ($largest, $smallest) = (-9e9,9e9); # + initialize to the wrong extremes if($use_brostad) { ($largest, $smallest) = (sort {$b <=> $a } @array)[0,-1]; # + [brostad]'s [id://1203655]: reverse sort, return the first and last + elements } else { for my $v (@array) { # + [anonymous monk]'s [id://1203660]: single pass through loop, withou +t sorting; more efficient than brostad's single sort $largest = $v if $v > $largest; $smallest = $v if $v < $smallest; } } print "\nThe largest number is: "; print $largest, "\n"; # + [pryrt]: largest is now scalar, not array print "The smallest number is: "; print $smallest; # + [pryrt]: smallest is now scalar, not array print "The average of the numbers is: "; printf "%.1f\n", my $average = average(@array); # + [pryrt]: only call average() once per dataset print "\n"; foreach (@array) { chomp; if ($average > $_) { print "$_\t is below average.\n"; } elsif ($average < $_) { print "$_\t is above average.\n"; } elsif ($average == $_) { # + [AnomalousMonk]'s [id://1203631]'s fix: comparison, not assigment print "$_\t is equal to average.\n"; } } print "\nDo it again? (Yes or No): "; chomp (my $yesno=<STDIN>); if($yesno ne 'Yes') { print "Goodbye.\n"; exit; } } sub average { if (@_) { # + [pryrt]'s [id://1203627] my @temp = @_; my $sum = 0; foreach (@temp) { $sum = $sum + $_; } return $sum/@temp; } }

Replies are listed 'Best First'.
Re^2: resetting a foreach loop!
by AnomalousMonk (Archbishop) on Nov 17, 2017 at 18:08 UTC
    my ($largest, $smallest) = (-9e9,9e9); # in +itialize to the wrong extremes ... for my $v (@array) { # [a +nonymous monk]'s [id://1203660]: single pass through loop, without so +rting; more efficient than brostad's single sort $largest = $v if $v > $largest; $smallest = $v if $v < $smallest; }

    The only quarrel I have with this implementation is that it depends on assumptions about the smallest and largest representable numbers (the wrongest extremes) in the system. Even if the assumptions are true in a given system, all bets are off if you move, e.g., to a different platform: from a 32-bit float to a 64-, 80- or who-knows-how-many-bit float. And if they're not true:

    c:\@Work\Perl\monks>perl -wMstrict -le "my @array = (-9e9-123, -9e9-234); ;; my ($largest, $smallest) = (-9e9, 9e9); ;; for my $elem (@array) { $largest = $elem if $elem > $largest; $smallest = $elem if $elem < $smallest; } print qq{smallest: $smallest; largest: $largest}; " smallest: -9000000234; largest: -9000000000
    Taking the initial smallest/largest value from the array itself is bulletproof: either the initializer is already the smallest/largest value, or some other value will be found in the array that is smaller/larger.
    c:\@Work\Perl\monks>perl -wMstrict -le "my @array = (-9e9-123, -9e9-234); ;; my ($largest, $smallest) = ($array[0], $array[0]); ;; for my $elem (@array) { $largest = $elem if $elem > $largest; $smallest = $elem if $elem < $smallest; } print qq{smallest: $smallest; largest: $largest}; " smallest: -9000000234; largest: -9000000123


    Give a man a fish:  <%-{-{-{-<

      You're right. I should have pointed the dangers of my assumptions in my post. I hadn't even thought of just using the 0th element of the array twice to initialize the largest/smallest -- but that's the best choice for the single-loop version. Thanks.

      TIMTOWTDI: with perl 5.24 and newer, you could set those to my ($largest, $smallest) = (-POSIX::Inf, +POSIX::Inf): nothing's bigger or smaller than Infinity, after all. :-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1203671]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (8)
As of 2024-04-23 10:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found