http://www.perlmonks.org?node_id=1035026


in reply to Duplicate Results from Subroutine

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

Replies are listed 'Best First'.
Re^2: Duplicate Results from Subroutine
by zenrhino (Initiate) on May 24, 2013 at 00:55 UTC
    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.
        Or, simplified by grep:
        sub abv { my $avg = avg(@_); return grep $_ > $avg, @_; }
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ