Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

<SOLVED>Dereferencing arrays

by divitto (Novice)
on Mar 19, 2014 at 19:59 UTC ( #1078973=perlquestion: print w/ replies, xml ) Need Help??
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?

Comment on <SOLVED>Dereferencing arrays
Select or Download Code
Re: Dereferencing arrays
by BrowserUk (Pope) on Mar 19, 2014 at 20:10 UTC

    The first thing that screamed at me when reading your code is that this:

    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.

      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++; } }

        Your problems are pretty much all caused by misuse of prototypes. Just get rid of them. There is rarely a good reason to give Perl subs prototypes.

        use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

        Compare this code (which works) with your version and ask questions about any differences you do not understand:

        #!/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.
Re: Dereferencing arrays
by kennethk (Monsignor) 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.

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

      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 :)

        I understand that the working code changed the merge method to take references but i don't understand why. could you explain that to me? Sorry for the trouble everyone perl's grammer and syntax is confusing for a newbie to it like myself.

Re: Dereferencing arrays
by AnomalousMonk (Abbot) on Mar 19, 2014 at 20:49 UTC

      i will check your links, the reason i tried using protypes was i read online somewhere that they were needed for recursive methods. I wont make that mistake again.

        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.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (8)
As of 2014-09-17 18:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (94 votes), past polls