Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Duplicate Results from Subroutine

by zenrhino (Initiate)
on May 23, 2013 at 20:12 UTC ( [id://1035019]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings, Monks.

I'm working my way through Learning Perl 6th Ed and doing an expansion of Probs. 1-3 on pp. 78.

My problem is that is I use the @abvlist array as seen on list 16, I get the correct answer. If I call the function directly as on line 17, I get a duplicate set of the answer. I am at a loss as to why this happens.

I suspect, that as with most things in Perl, it's going to be something simple and small I'm looking right over.

Run as is, I get the following:

The count of numbers in @numlist is 8.
The total of @numlist is 40.
The mean average of @numlist is 5.
The list of numbers in @numlist over the mean is 7,9.
The list of numbers that will probably be duplicates in @numlist over the mean is 7,9,7,9.
The standard deviation of numbers in @numlist is 2.
Finished in 0.1s

I get the same results from the commandline in powershell as I do from the build run in ST2.

I've searched for "duplicate results from subroutine" and "duplicate results from function" and didn't see anything.

All the best,

-ZR

#!/C:\Perl64\bin\perl.exe use strict; use warnings; my @numlist = qw(2 4 4 4 5 5 7 9); my $numlist_avg = avg(@numlist); my @cands; my @abvlist = abv(@numlist); my $sigma = std_dev(@numlist); my @squares; my $len = $#numlist + 1; print "The count of numbers in \@numlist is ", $#numlist + 1, "\.\n"; print "The total of \@numlist is ", total(@numlist), "\.\n"; print "The mean average of \@numlist is ", avg(@numlist), "\.\n"; print "The list of numbers in \@numlist over the mean is ", join(',', + @abvlist), "\.\n"; print "The list of numbers that will probably be duplicates in \@numli +st over the mean is ", join(',', abv(@numlist)), "\.\n"; print "The standard deviation of numbers in \@numlist is ", $sigma, "\ +.\n"; sub total { my $endresult = 0; foreach my $x (@numlist) { $endresult += $x; } return $endresult; } sub avg { my $len1 = $#numlist + 1; return total(@numlist) / $len1; } sub abv { foreach my $cand (@numlist) { if ($cand > $numlist_avg) { push(@cands, $cand); } } return @cands; } sub std_dev { my $len2 = $#numlist + 1; foreach my $num (@numlist) { my $step1 = $num - $numlist_avg; my $step2 = $step1 * $step1; push(@squares, $step2); } my $start2 = 0; foreach my $num2 (@squares) { $start2 += $num2; } return sqrt($start2 / $len2); }

Replies are listed 'Best First'.
Re: Duplicate Results from Subroutine
by stephen (Priest) on May 23, 2013 at 21:08 UTC

    To fix this specific problem, you need to localize @cands in abv() rather than up at the top of the script.

    sub abv { # Move from top of the script down to here my @cands = (); foreach my $cand (@numlist) { if ($cand > $numlist_avg) { push(@cands, $cand); } } return @cands; }

    Each time you call abv(), it remembers @cands from the last time you call it, and returns the duplicate values as well as the new ones.

    It's a good idea to localize your variables to the smallest possible block. Declare them in the subroutine that's using them.

    You're also assuming that $numlist_avg has already been determined. If you tried calling abv() before setting $numlist_avg, you might wind up with a hard-to-trace error.

    While we're at it, you're passing @numlist to the subroutine as an argument, but not actually using that argument. If you called abv(1,2,3) it would still go over @numlist to get the result. So, instead, you should do:

    sub abv { my (@numlist_args) = @_; my @cands = (); my $avg = avg(@numlist_args); foreach my $cand (@numlist_args) { if ($cand > $avg) { push(@cands, $cand); } } return @cands; }
    Good luck!

    stephen

      Daaaang.

      That's like five lessons for the price of one.
      I did bang my head against ways to generalize the subroutines not using @numlist, but figured asking two questions at once would be selfish.

      So if I have this right, @_ holds the list of parameters passed to the abv subroutine, and we know it gets passed as a list because it ends up as my (@numlist_args) and not my @numlist_args which would pass a scalar. So then the foreach loop works on whatever is passed as paramaters.

      I took your help and also applied it to the std_dev subroutine which had the effect of letting me get rid of all of the hardcoded variables that I had originally and making the subroutines easier to read.

      Thank you very much!

      -Clint

        So if I have this right, @_ holds the list of parameters passed to the abv subroutine.
        You got it, here's a version that uses the special variables $_ and @_
        sub abv { my $avg = avg(@_); my @cands = (); foreach (@_) { ($_ > $avg) and push(@cands, $_); } return @cands; }
        I flicked the if statement into a logical and, for each iteration of the foreach $_ will be the same as $cand was in the original function.
Re: Duplicate Results from Subroutine
by dbuckhal (Chaplain) on May 24, 2013 at 06:03 UTC
    Looks like they got you taken care of, so I thought I would pass a little tip about finding array size
    sub avg { my $len1 = $#numlist + 1; return total(@numlist) / $len1; }
    You can get the array length by this:
    my $len1 = @numlist;
    ... which is the scalar value of your array, which is the size.

    Enjoy Learning Perl!

Log In?
Username:
Password:

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

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

    No recent polls found