2

I am trying to pass some arguments into a sub routine

sub mean 
{
my (@values, $chan1, $chan2, $chan3, $chan4) = @_;
print   $chan1, $chan2, $chan3, $chan4;
my $ave_value = sum($values[$chan1],$values[$chan2],$values[$chan3],$values[$chan4])/@values;
}

with a call of

 push (@avg_value , mean(@datachunk,$subchannel[0],$subchannel[1],$subchannel[2],$subchannel[3]));

I am getting error uninitialized value in an array element. I am assuming it because of the way I Am trying read in values. Is this the proper approach?

2 Answers 2

3

Your array assignment is eating up all the parameters.

For example, in the following, $foo and $bar will always be undefined, and @array will contain 4 elements:

my (@array, $foo, $bar) = (1,2,3,4);

Here are two potential solutions:

1) Put scalars first, and then your array:

sub mean  {
    my ($chan1, $chan2, $chan3, $chan4, @values) = @_;
    print   $chan1, $chan2, $chan3, $chan4;
    my $ave_value = sum(@values[$chan1, $chan2, $chan3, $chan4])/@values;
}

# Calling method:
mean($subchannel[0], $subchannel[1], $subchannel[2], $subchannel[3], @datachunk)

2) Alternatively, you can pass the array by reference:

sub mean  {
    my ($arrayref, $chan1, $chan2, $chan3, $chan4) = @_;
    print   $chan1, $chan2, $chan3, $chan4;
    my $ave_value = sum(@{$arrayref}[$chan1, $chan2, $chan3, $chan4]) / @$arrayref;
}

# Calling method:
mean(\@datachunk, $subchannel[0], $subchannel[1], $subchannel[2], $subchannel[3])

However, the tightest solution is to restyle your code. All you want is the average of a list. Therefore, just pass a list directly instead of the array with index values.

sub mean  {
    return @_ ? sum(@_) / @_ : die "Mean of 0 numbers is undefined";
}

# Calling method:
mean(@datachunk[@subchannel[0..3]])
Sign up to request clarification or add additional context in comments.

3 Comments

undef makes more sense than zero when finding the mean of nothing. Dying even more so.
Given the OP is pushing means into an array, I'd probably lean toward using (). However, what is important is that he just deal with it in some intentional way that he chooses. Including an explicit die in the example code communicates that best.
I disagree with returning an empty list from a function expected to return a scalar. It causes things to fail badly sometimes.
3

The problem is that Perl isn't as clever as Ruby, so when you gather the parameters to mean with the assignment

my (@values, $chan1, $chan2, $chan3, $chan4) = @_;

you assign the whole of @_ to @values leaving $chan1, $chan2 etc. set to undef

In general, and especially if you are combining array parameters with scalars, you should pass arrays by reference. So your subroutine could be

sub mean {
  my ($values, $chan1, $chan2, $chan3, $chan4) = @_;
  print "$chan1, $chan2, $chan3, $chan4\n";
  my $avg = sum(
    $values->[$chan1],
    $values->[$chan2],
    $values->[$chan3],
    $values->[$chan4]
  ) / @values;
}

and you would call it as

push(@avg_value, mean(
  \@datachunk,
  $subchannel[0], $subchannel[1], $subchannel[2], $subchannel[3]
));

However, your mean subroutine would be much more generally useful if you passed just the list of values. For instance, if you had mean defined as

sub mean { sum(@_) / @_ }

then you could call it using an array slice, like this

push(@avg_value, mean(@datachunk[@subchannel[0..3]]));

or, if that is too much for you then split out the slices

my @chunk_indices = @subchannel[0..3];
my @values = @datachunk[@chunk_indices];
push @avg_value, mean(@values));

I hope this helps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.