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

i am in the process of learning Perl. Here's the piece of code i tried.. but does not work... I am trying to compare the list of numbers to their average. "@greatern = $_ " does not seem to work below. It does not save all the values into the array. Alternatively when i use "push", there is a whitespace before each array variable. I am not able to understand the problem here and would like to make the program work in both ways. please help.. *************************************
#!/usr/bin/perl sub addition { my(@mynumbers) = @_ ; foreach (@mynumbers){ $sum += $_ ; } return $sum ; } sub avg { my(@mynumbers) = @_ ; $aver = addition(mynumbers)/($#mynumbers+1) ; return $aver ; } ## ##BELOW DOES NOT WORK AS I WISH. ## @numlist = <STDIN> ; $total = addition(@numlist) ; $average = avg(@numlist) ; $n = 0 ; foreach (@numlist) { if ($_ > $average) { @greater[n] = $_ ; # push @greater,$_ ; # print "greater is @greater \n" ; $n++ ; } } if ( $n > 0 ) { print "Following numbers are greater than the average:\n" ; print "@greater array size is $#greater\n" } else { print "All your numbers are less than or equal to the average\n" ; }
************************************

Replies are listed 'Best First'.
Re: cheesy comparison program not working!!
by andreas1234567 (Vicar) on Sep 28, 2007 at 10:18 UTC
    Add use strict; use warnings; on line 2 of your script, and you'll get a hint of what's wrong:
    Scalar value @greater[n] better written as $greater[n] at line 30. Possible unintended interpolation of @greater in string at line 39. Bareword "n" not allowed while "strict subs" in use at line 30.
Re: cheesy comparison program not working!!
by cdarke (Prior) on Sep 28, 2007 at 10:19 UTC
    use strict; use warnings;
    Always! They help, honest. They really do!

    Here's a few problems with your code in no particular order:

    $aver = addition(mynumbers)/($#mynumbers+1) ;in sub avg has a missing '@', should be: $aver = addition(@mynumbers)/($#mynumbers+1) ;
    Reading @numlist from STDIN allows you to enter each number, followed by <RETURN>. When you have entered each number you press <EOD>, which is usually <CTRL>D on UNIX and <CTRL>Z on Windows. I suspect you are entering each number on the same line, separated by a space (can't be certain though).

    There are other tweeks you could make, but try these for now.
      Thank You so much for your quick responses!! After amending the program, it now seems to work..
      #!/usr/bin/perl use strict ; use warnings ; sub addition { my $sum ; my(@mynumbers) = @_ ; foreach (@mynumbers){ $sum += $_ ; } return $sum } sub avg { my $aver ; my(@mynumbers) = @_ ; $aver = addition(@mynumbers)/($#mynumbers+1) ; print "$aver\n" ; return $aver ; } ## ##THIS NOW WORKS!!! ## my (@numlist, $total, $average, $n, @greater) ; chomp(@numlist = <STDIN>) ; $total = addition(@numlist) ; $average = avg(@numlist) ; $n = 0 ; foreach (@numlist) { if ($_ > $average) { $greater[$n] = $_ ; # push @greater,$_ ; $n++ ; } } if ( $n > 0 ) { print "Following numbers are greater than the average: " ; print "@greater. Array size is $#greater\n" #IS THERE A WAY I CA +N USE "$#greater+1" IN SOME WAY HERE? } else { print "All your numbers are less than or equal to the average\n" ; }
      Now how do i use this above...
      print "$#greater+1" ?
      obviously this does not work as-...is
      All said and done.. is this the best way to write the program in terms of coding standards?
        Now how do i use this above... print "$#greater+1" ?

        does not work because you have quotes around it. Operators like + do not get executed inside quotes. Anyhow, it is not the greatest way to find the number of elements in an array, use the array in scalar context instead. There are many ways to do this, one of the less obscure is: print scalar(@greater),"\n";
        If you are seriously interested in coding practices, here are some items I have found to be useful:
Re: cheesy comparison program not working!!
by jeanluca (Deacon) on Sep 28, 2007 at 10:16 UTC
    A quick look at your code tells me that you should change
    @greater[n] = $_ ;
    into
    $greater[n] = $_ ;
    Thats how you access array elements.
    Furthermore, the reason that push doesn't do what you want is because there a \n after each number. Put
    chop ;
    in the for-loop to remove it, and push will work as you want!!

    LuCa
      "chomp" !! how can i miss it?!

      I am refering "Learning Perl, 4th Edition".. not surprisingly, the author mentions.. "Every week or two a message appears on the newsgroup comp.lang.perl.misc with a subject-line like this. Without reading the message, we know the program used double quotes around an array containing unchomped strings" !!! LOL

      Stupid me!!
Re: cheesy comparison program not working!!
by svenXY (Deacon) on Sep 28, 2007 at 11:26 UTC
    Hi,
    ++others for the corrections and suggestions.
    This is certainly not the best in terms of coding standards or algorythms, but should give you an idea as to where this could go...

    Regards,
    svenXY
Re: cheesy comparison program not working!!
by andreas1234567 (Vicar) on Sep 28, 2007 at 20:16 UTC
    Two more tips to make your Perl more robust:
    • Check all input rigorously.
    • Create test scripts to ensure your code behaves as intended.
    --
    Andreas
Re: cheesy comparison program not working!!
by ww (Archbishop) on Sep 29, 2007 at 10:03 UTC
    Picky, but your lines 39 & 40,
    print "All your numbers are less than or equal to the average\n"
    reminds me of a fictional US town "where all the women are strong, all the men are good-looking, and all the children are above average."

    Your else { ... } clause can't execute, unless the numbers you input are all identical... in which case, that might be more easily determined by inspection than by keyboarding them.

    :-)

    More seriously, be wary of "believing your own propaganda," whether explicit, as in 39-40, or implicit.

    Update - fixed Garrison Keillor quote (was missing "where").