secJ
secJ

Reputation: 509

Perl: Anonymous Multi-Dimensional Arrays

NOTE: See the end of this post for final explanation.

This is probably a very basic question, but I'm still trying to master a few of the fundamentals regarding references in Perl, and came across something in the perldsc page that I'd like to confirm. The following code is in the Generating Array of Arrays section:

while ( <> ) {
   push @AoA, [ split ];
} 

Obviously, the <> operation in the while loop reads one line of input in at a time. I am assuming at this point that line is then put into an anonymous array via the [ ] brackets, we'll call this @zero. Then the split command places everything in a given line separated by whitespace within the array (e.g., the first word is assigned to $zero[0], the second to $zero[1] and so on). The scalar reference of @zero is then pushed onto @AoA.

The next line of input is passed via the <> operator and gets assigned to a completely new anonymous array (e.g. @one), and its scalar reference is pushed onto @AoA.

Once @AoA is populated, I could then access its contents with a nested foreach loop; the first iterating through the "rows" (e.g. for $row (@AoA)), and a second, inner loop, foreach to access the columns of that particular row.

The latter (accessing said "columns" would be done by dereferencing (e.g., for $column (@$row)) the particular $row being read by the previous, "outer" foreach loop.
Is my understanding correct? I'm assuming you could still access any element of the @AoA just as you would if it were assigned vs. being anonymous? That is $element = $AoA[8][1]; .

I'm want to verify my thought process here. Is the automatic declaration of a unique, anonymous array each time through the loop part of the autovivication in Perl? I guess that is what is throwing me off a bit. Thanks.

EDIT: Based on the comments below my understanding regarding the anonymous array is still unclear, so I want to take a shot at one more description to see if it meets everyone's understanding.

Starting with the push @AoA, [split]; statement, split takes in the line from $_ and returns a list parsed by whitepace. That list is captured by [ ], which then returns an array reference. That array reference (created by [ ]) is then pushed onto @AoA. Is this accurate re: [ ]? The next step (dereferencing / use of @AoA) was covered very well by @krico below.

FINAL ANSWER/EXPLANATION: Based on all of the comments / feedback here, some further research on my part, and testing it seems my understanding was correct. I'll break it down here, so others can easily reference it later. See @krico's response below for a more explicit code representation that follows the steps outlined here.

while ( <> ) {
    push @AoA, [ split ];
}
  1. One line of input is passed at a time to the <> operator
  2. The split function takes that line in via $_ and parses it based on whitespace (the default).
  3. split then returns a LIST.
  4. The [ ] is an anonymous array that provides the perl data structure for the List passed by split.
  5. The push @AoA pushes the reference to the anonymous array onto its queue as element $AoA[0] (the second anonymous array reference will be put into $AoA1, etc...).
  6. This continues through the entire input file. Once completed, @AoA is a 2D array, holding reference values (scalar values) to each of the previously generated anonymous arrays.
  7. From this point @AoA can be dereferenced appropriately to work with the underlying/reference elements taken in from the input file. The default dereferencing technique is CIRCUMFIX (see perlfef below); however as of 5.19 a new method of dereferencing is available and will be released in 5.20, POSTFIX. Articles are linked below.

References: Perl References Documentation, Perl References Tutorial, Perl References Question noted by @Eli Hubert, Mike Friedman's blog post about differences between arrays and lists, Upcoming Postfix dereferencing in Perl, and Postfix dereferencing Article

Upvotes: 4

Views: 320

Answers (2)

rickb
rickb

Reputation: 51

This is what is going on:

  1. The <> will put the line into the default variable $_
  2. The split function will read $_ and return an array
  3. The [ ] brackets will return a scalar, in it there will be a reference to that array
  4. That reference is then pushed into the @AoA array

When you do $AoA[8][2] you are implicitly dereferencing the scalar. It's the same as $AoA[8]->[2].

Upvotes: 2

krico
krico

Reputation: 5728

The same code a little more readeable and you should understand it.

my $line;
while ( $line = <STDIN> ) {
   my @parts = split $line;
   my $partsRef = \@parts;
   push @AoA, $partsRef;
}

Now, if you wanted to print the 2nd part of the 5th line you could say.

my $ref = @AoA[4];
my @parts = @$ref;
print $parts[1];

Get it?

Upvotes: 1

Related Questions