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

I can't figure this one out.

I would appreciate any help anyone can give.

This snippet below has a scalar reference pointing to an array. The second member of the array is a reference pointing to another array.

The code in question is:
$aray_size = scalar (@$states[ 1 ]);
After this line executes, my debugger says that $array_size is now an array, not a scalar holding the length of the array. Why???
my $states = [ ]; # Annonymous array constructed push @$states, 'Oregon'; print "@$states [ 0 ]\n"; my $city; my $cities = [ ]; # Inner annonymous array constructed push @$cities, "Portland"; push @$cities, "Salem"; push @$cities, "Bend"; push @$states, $cities; my $counter; my $array_size = scalar (@$states [ 1 ]); # here for ($counter = 0; $counter < $array_size; $counter++) { print "\t@$states [ 1 ]->\[$counter\]\n"; }

Replies are listed 'Best First'.
Re: Changling here?
by GrandFather (Saint) on May 30, 2008 at 02:53 UTC

    @$states [ 1 ] is an array slice (see Slices). The syntax you require is my $array_size = @{$states->[1]}. Note that $array_size is a scalar so you don't need the scalar operator.


    Perl is environmentally friendly - it saves trees
Re: Changling here?
by jdporter (Paladin) on May 30, 2008 at 02:58 UTC

    Quite simply, because array slices are not arrays.

    Consider the equivalent using a regular array instead of a ref:

    my @states = ( [], [] ); my $aray_size = @states[1];
    Even though we know that the element at $states[1] is an array, it doesn't matter; the slice is returning the single-element list ([]), and thus the scalar $aray_size receives the last element thereof - the (second, inner) arrayref.

    What you need to do is make sure you've actually got the array-ref which is the second element of the (outer) array, dereference that, and subject that to the scalar() operator. Something like

    my $aray_size = @{ ${$states}[ 1 ] }; # or my $aray_size = @{ $states->[ 1 ] };
    (Note that the scalar op is implicit, due to the context transmitted by the assignment operator from the scalar variable on the LHS.)

    A word spoken in Mind will reach its own level, in the objective world, by its own weight
Re: Changling here?
by hangon (Deacon) on May 30, 2008 at 03:33 UTC

    The for loop at the end was a bit of a puzzler because you didn't put your code between <code> </code> tags. See this node.

    # original for ($counter = 0; $counter < $array_size; $counter++) { print "\t@$states [ 1 ]->\$counter\\n"; } # did you really mean this? for ($counter = 0; $counter < $array_size; $counter++) { print "\t@$states [ 1 ]->[$counter]\n"; }

    If so, once you've got slices and dereferencing under control, this is a clearer and more perlish way to iterate over an array.

    for my $city (@{ $states->[1] }) { print "\t$city\n"; } # or for (@{ $states->[1] }) { print "\t$_\n"; }

      or:

      print "\t$_\n" for @{$states->[1]};

      Perl is environmentally friendly - it saves trees