divitto has asked for the wisdom of the Perl Monks concerning the following question:
<SOLVED>
Let me explain, I know that @$arrayRef will return the array that the reference is pointing to. I've also tried @{ $arrayRef } as well. i've tested both of these scenarios in a seperate script just to make sure they work on my machine and they do. (not suprisingly) When i try to run my actual script (below) i get a weird error, that has stumped me for the last two days. I could use some wisdom, Thank you in advance.
here's the code:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
#protos
sub mergeSort( \@ );
my @unsortedData = ( 5, 4, 7, 2, 1, 3, 6, 9, 8, 10 );
# show the original data to screen
for( @unsortedData ) {
print "$_ ";
}
print "\n";
my $sortedData = &mergeSort( \@unsortedData );
# show the new data to screen
for( @$sortedData ) {
print "$_ ";
}
print "\n";
### dereferencing of arrays isnt working in below method
sub mergeSort( \@arrayRef ) {
my ( $data ) = @_;
if( @$data < 2 ) { return $data; } # if there is less then two it
+ems it's already sorted!!
use integer;
#split the array into two parts
my $middle = @$data / 2;
print "middle: $middle\n";
my @leftSide = ();
print "LeftSide:\n";
for( my $i = 0; $i < $middle; $i++ ) {
@leftSide[$i] = @$data[$i];
print "@leftSide[$i] ";
}
print "\n";
my @rightSide = ();
print "RightSide:\n";
for( my $i = $middle; $i < @$data; $i++ ) {
@rightSide[$i - $middle] = @$data[$i];
print "@rightSide[$i - $middle] ";
}
print "\n";
&mergeSort( @leftSide );
&mergeSort( @rightSide );
&merge( @leftSide, @rightSide, $data );
return $data;
}
sub merge {
my ( @groupA, @groupB, $dataRef ) = @_;
my $i = 0; my $j = 0; my $k = 0;
while( $i < @groupA && $j < @groupB ) {
if( @groupA[$i] <= @groupB[$j] ) {
@$dataRef[$k] = @groupA[$i];
$i++;
}
else {
@$dataRef[$k] = @groupB[$j];
$j++;
}
$k++;
}
while( $i < @groupA ) {
@$dataRef[$k] = @groupA[$i];
$i++;
$k++;
}
while( $j < @groupB ) {
@$dataRef[$k] = @groupB[$j];
$j++;
$k++;
}
}
I was trying to implement a merge sort. (i'm aware the default for perl's sort() is a merge sort. thats not the point)
the problem comes from my mergeSort subroutine either when i test that the array is less then 2 or when i try to get the size of the array for my $middle calculation. the output i get is:
5 4 7 2 1 3 6 9 8 10
middle: 5
LeftSide:
5 4 7 2 1
RightSide:
3 6 9 8 10
Can't use string ("5") as an ARRAY ref while "strict refs" in use at m
+ergeSort.pl line 34.
it's probably just me getting lost in context but i don't think im using a string as an array reference, any ideas?
Re: Dereferencing arrays
by BrowserUk (Patriarch) on Mar 19, 2014 at 20:10 UTC
|
sub mergeSort( \@arrayRef ) {
Isn't a legal Perl construct. And sure enough, running a syntax check on your code exactly as posted produces: C:\test>perl -c junk92.pl
Illegal character in prototype for main::mergeSort : \@arrayRef at jun
+k92.pl line 27.
Scalar value @leftSide[$i] better written as $leftSide[$i] at junk92.p
+l line 40.
Scalar value @leftSide[$i] better written as $leftSide[$i] at junk92.p
+l line 41.
Scalar value @rightSide[$i - $middle] better written as $rightSide[$i
+- $middle] at junk92.pl line 47.
Scalar value @rightSide[$i - $middle] better written as $rightSide[$i
+- $middle] at junk92.pl line 48.
Prototype mismatch: sub main::mergeSort (\@) vs (\@arrayRef) at junk92
+.pl line 55.
Scalar value @groupA[$i] better written as $groupA[$i] at junk92.pl li
+ne 62.
Scalar value @groupB[$j] better written as $groupB[$j] at junk92.pl li
+ne 62.
Scalar value @groupA[$i] better written as $groupA[$i] at junk92.pl li
+ne 63.
Scalar value @groupB[$j] better written as $groupB[$j] at junk92.pl li
+ne 67.
Scalar value @groupA[$i] better written as $groupA[$i] at junk92.pl li
+ne 73.
Scalar value @groupB[$j] better written as $groupB[$j] at junk92.pl li
+ne 78.
junk92.pl syntax OK
Which means you've either been ignoring the messages; or you added strict and warnings for posting.
Fix that lot, then come back and someone will explain to you why this will never work: my ( @groupA, @groupB, $dataRef ) = @_;
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
That was me messing with prototypes another topic im still learning in perl. however my code above is directly copy pasted from my real code i changed nothing and i did not just add use strict or use warnings for posting, yet i get nothing like what you got. ill fix the issues, but this leads me to think something is wrong with my enviorment.. EDIT: Oops lol the warnings were scrolling off screen in my terminal i feel dumb. Still get the error though.
heres the new code:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
#protos
# sub mergeSort( \@ );
my @unsortedData = ( 5, 4, 7, 2, 1, 3, 6, 9, 8, 10 );
# show the original data to screen
for( @unsortedData ) {
print "$_ ";
}
print "\n";
my $sortedData = &mergeSort( \@unsortedData );
# show the new data to screen
for( @$sortedData ) {
print "$_ ";
}
print "\n";
### dereferencing of arrays isnt working in below method
sub mergeSort {
my ( $data ) = @_;
if( @$data < 2 ) { return $data; } # if there is less then two it
+ems it's already sorted!!
use integer;
#split the array into two parts
my $middle = @$data / 2;
print "middle: $middle\n";
my @leftSide = ();
print "LeftSide:\n";
for( my $i = 0; $i < $middle; $i++ ) {
$leftSide[$i] = @$data[$i];
print "$leftSide[$i] ";
}
print "\n";
my @rightSide = ();
print "RightSide:\n";
for( my $i = $middle; $i < @$data; $i++ ) {
$rightSide[$i - $middle] = @$data[$i];
print "$rightSide[$i - $middle] ";
}
print "\n";
&mergeSort( @leftSide );
&mergeSort( @rightSide );
&merge( @leftSide, @rightSide, $data );
return $data;
}
sub merge {
my ( @groupA, @groupB, $dataRef ) = @_;
my $i = 0; my $j = 0; my $k = 0;
while( $i < @groupA && $j < @groupB ) {
if( $groupA[$i] <= $groupB[$j] ) {
@$dataRef[$k] = $groupA[$i];
$i++;
}
else {
@$dataRef[$k] = $groupB[$j];
$j++;
}
$k++;
}
while( $i < @groupA ) {
@$dataRef[$k] = $groupA[$i];
$i++;
$k++;
}
while( $j < @groupB ) {
@$dataRef[$k] = $groupB[$j];
$j++;
$k++;
}
}
| [reply] [d/l] |
|
| [reply] |
|
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my @unsortedData = ( 5, 4, 7, 2, 1, 3, 6, 9, 8, 10 );
# show the original data to screen
for( @unsortedData ) {
print "$_ ";
}
print "\n";
my $sortedData = mergeSort( \@unsortedData );
# show the new data to screen
for( @$sortedData ) {
print "$_ ";
}
print "\n";
### dereferencing of arrays isnt working in below method
sub mergeSort {
my ( $data ) = @_;
if( @$data < 2 ) { return $data; } # if there is less then two it
+ems it's already sorted!!
use integer;
#split the array into two parts
my $middle = @$data / 2;
print "middle: $middle\n";
my @leftSide = ();
print "LeftSide:\n";
for( my $i = 0; $i < $middle; $i++ ) {
$leftSide[$i] = @$data[$i];
print "$leftSide[$i] ";
}
print "\n";
my @rightSide = ();
print "RightSide:\n";
for( my $i = $middle; $i < @$data; $i++ ) {
$rightSide[$i - $middle] = @$data[$i];
print "$rightSide[$i - $middle] ";
}
print "\n";
mergeSort( \@leftSide );
mergeSort( \@rightSide );
merge( \@leftSide, \@rightSide, $data );
return $data;
}
sub merge {
my ( $groupA, $groupB, $dataRef ) = @_;
my $i = 0; my $j = 0; my $k = 0;
while( $i < @$groupA && $j < @$groupB ) {
if( $groupA->[$i] <= $groupB->[$j] ) {
@$dataRef[$k] = $groupA->[$i];
$i++;
}
else {
@$dataRef[$k] = $groupB->[$j];
$j++;
}
$k++;
}
while( $i < @$groupA ) {
@$dataRef[$k] = $groupA->[$i];
$i++;
$k++;
}
while( $j < @$groupB ) {
@$dataRef[$k] = $groupB->[$j];
$j++;
$k++;
}
}
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
|
|
|
Re: Dereferencing arrays
by kennethk (Abbot) on Mar 19, 2014 at 20:23 UTC
|
One thing that jumps out at me is that the code issues a lot of warnings, which makes me think you aren't actually running with warnings in place. You use a lot of array slices (e.g. @leftSide[$i] in place of $leftSide[$i]) and you use a pointless and malformed prototype for mergeSort. You also use & syntax for your method call, which dodges the prototype anyway. Please make sure you post the code you are using, and don't just slap warnings on for a post.
When I run your code, the error you cite occurs on my line 30. It hits because when you call mergeSort on line 51, @leftSide array has 5 elements. Since you've used Prototypes, mergeSort expects a single scalar. However, you undermine the protoype system by invoking your method with &, so Perl stuffs your array in scalar context; thus the array length of 5. The general solution is don't use prototypes unless you actually know how to use them. If you change your code to read:
mergeSort( @leftSide );
mergeSort( @rightSide );
merge( @leftSide, @rightSide, $data );
You will solve this particular issue, though your sort will still fail for the reasons that BrowserUk hints at.
#11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.
| [reply] [d/l] [select] |
Re: Dereferencing arrays
by AnomalousMonk (Archbishop) on Mar 19, 2014 at 20:49 UTC
|
| [reply] |
|
| [reply] |
|
No, this isn't true, prototypes are not needed for recursive subroutine calls.The typical example of recursive routines is the calculation of the factorial of a number, which may be coded this way:
#!/usr/bin/perl
use strict;
use warnings;
my $input = shift;
chomp $input;
print factorial($input);
sub factorial {
my $val = shift;
return 1 if $val == 0 or $val == 1;
return $val * factorial($val - 1);
}
As you can see, no prototype needed. Prototypes can be useful for some advanced constructs, but, as a beginner, just don't use them, at least until you are no longer a beginner and you really know what they are and what they really do.
| [reply] [d/l] |
Re: Dereferencing arrays
by hazylife (Monk) on Mar 19, 2014 at 20:25 UTC
|
It's because of the ampersands, see perlsub:
Not only does the & form make the argument list optional, it also disables any prototype checking on arguments you do provide.
$ perl -le 'sub foo(\@) { ref(shift) ? "ref" : "not a ref" }; @arr=(1.
+.3); print foo(@arr)'
ref
$ perl -le 'sub foo(\@) { ref(shift) ? "ref" : "not a ref" }; @arr=(1.
+.3); print &foo(@arr)'
not a ref
| [reply] [d/l] |
|
like i said in a previous post (although maybe not fast enough for you to catch it ) i didn't add strict and warnings just for posting. I've adjusted all the flaws everyone has pointed out. I guess i was confused i thought you always had to use the ampersand for method calls. I still get the same string as an array reference error. can somebody please point me in the right direction on that now?
EDIT: didnt see the code example, working on it :)
| [reply] |
|
| [reply] |
|
|