summaryrefslogtreecommitdiff
path: root/pod/perllol.pod
diff options
context:
space:
mode:
authorTom Christiansen <tchrist@perl.com>2011-05-02 09:24:49 -0400
committerJesse Vincent <jesse@bestpractical.com>2011-05-18 14:59:37 -0400
commit21863e7e0890fa3f55e9efd85a0746d312e7dc53 (patch)
tree2ec0c32210fdcc70beca393fca3ee0f260d1b960 /pod/perllol.pod
parentf4750dabedb3961d2aa3fec0bc3a92de1ebc06b6 (diff)
downloadperl-21863e7e0890fa3f55e9efd85a0746d312e7dc53.tar.gz
perllol doc updates from tchrist.
Diffstat (limited to 'pod/perllol.pod')
-rw-r--r--pod/perllol.pod157
1 files changed, 121 insertions, 36 deletions
diff --git a/pod/perllol.pod b/pod/perllol.pod
index 58d532b12f..8c6c0563f8 100644
--- a/pod/perllol.pod
+++ b/pod/perllol.pod
@@ -6,23 +6,24 @@ perllol - Manipulating Arrays of Arrays in Perl
=head2 Declaration and Access of Arrays of Arrays
-The simplest thing to build is an array of arrays (sometimes imprecisely
-called a list of lists). It's reasonably easy to understand, and
-almost everything that applies here will also be applicable later
-on with the fancier data structures.
+The simplest two-level data structure to build in Perl is an array of
+arrays, sometimes casually called a list of lists. It's reasonably easy to
+understand, and almost everything that applies here will also be applicable
+later on with the fancier data structures.
An array of an array is just a regular old array @AoA that you can
get at with two subscripts, like C<$AoA[3][2]>. Here's a declaration
of the array:
+ use 5.010; # so we can use say()
+
# assign to our array, an array of array references
@AoA = (
- [ "fred", "barney" ],
- [ "george", "jane", "elroy" ],
- [ "homer", "marge", "bart" ],
+ [ "fred", "barney", "pebbles", "bambam", "dino", ],
+ [ "george", "jane", "elroy", "judy", ],
+ [ "homer", "bart", "marge", "maggie", ],
);
-
- print $AoA[2][2];
+ say $AoA[2][1];
bart
Now you should be very careful that the outer bracket type
@@ -33,11 +34,11 @@ but rather just a reference to it, you could do something more like this:
# assign a reference to array of array references
$ref_to_AoA = [
[ "fred", "barney", "pebbles", "bambam", "dino", ],
- [ "homer", "bart", "marge", "maggie", ],
[ "george", "jane", "elroy", "judy", ],
+ [ "homer", "bart", "marge", "maggie", ],
];
-
- print $ref_to_AoA->[2][2];
+ say $ref_to_AoA->[2][1];
+ bart
Notice that the outer bracket type has changed, and so our access syntax
has also changed. That's because unlike C, in perl you can't freely
@@ -88,16 +89,18 @@ array in it.
$AoA[$i] = [ @tmp ];
}
-It's very important that you make sure to use the C<[]> array reference
-constructor. That's because this will be very wrong:
+It's important you make sure to use the C<[ ]> array reference
+constructor. That's because this wouldn't work:
- $AoA[$i] = @tmp;
+ $AoA[$i] = @tmp; # WRONG!
-You see, assigning a named array like that to a scalar just counts the
-number of elements in @tmp, which probably isn't what you want.
+The reason that doesn't do what you want is because assigning a
+named array like that to a scalar is taking an array in scalar
+context, which means just counts the number of elements in @tmp.
-If you are running under C<use strict>, you'll have to add some
-declarations to make it happy:
+If you are running under C<use strict> (and if you aren't, why in
+the world aren't you?), you'll have to add some declarations to
+make it happy:
use strict;
my(@AoA, @tmp);
@@ -118,14 +121,14 @@ if you knew where you wanted to put it:
my (@AoA, $i, $line);
for $i ( 0 .. 10 ) {
$line = <>;
- $AoA[$i] = [ split ' ', $line ];
+ $AoA[$i] = [ split " ", $line ];
}
or even just
my (@AoA, $i);
for $i ( 0 .. 10 ) {
- $AoA[$i] = [ split ' ', <> ];
+ $AoA[$i] = [ split " ", <> ];
}
You should in general be leery of using functions that could
@@ -134,7 +137,7 @@ such. This would be clearer to the casual reader:
my (@AoA, $i);
for $i ( 0 .. 10 ) {
- $AoA[$i] = [ split ' ', scalar(<>) ];
+ $AoA[$i] = [ split " ", scalar(<>) ];
}
If you wanted to have a $ref_to_AoA variable as a reference to an array,
@@ -165,14 +168,45 @@ If you wanted just to append to a row, you'd have
to do something a bit funnier looking:
# add new columns to an existing row
- push @{ $AoA[0] }, "wilma", "betty";
+ push @{ $AoA[0] }, "wilma", "betty"; # explicit deref
+
+Prior to Perl 5.14, this wouldn't even compile:
+
+ push $AoA[0], "wilma", "betty"; # implicit deref
+
+How come? Because once upon a time, the argument to push() had to be be a
+real array, not just a reference to one. That's no longer true. In fact,
+the line marked "implicit deref" above works just fine--in this
+instance--to do what the one that says explicit deref did.
+
+The reason I said "in this instance" is because that I<only> works
+because C<$AoA[0]> already held an array reference. If you try that on an
+undefined variable, you'll take an exception. That's because the implicit
+derefererence will never autovivify an undefined variable the way C<@{ }>
+always will:
-Notice that I I<couldn't> say just:
+ my $aref = undef;
+ push $aref, qw(some more values); # WRONG!
+ push @$aref, qw(a few more); # ok
- push $AoA[0], "wilma", "betty"; # WRONG!
+If you want to take advantage of this new implicit dereferencing behavior,
+go right ahead: it makes code easier on the eye and wrist. Just understand
+that older releases will choke on it during compilation. Whenever you make
+use of something that works only in some given release of Perl and later,
+but not earlier, you should place a prominent
-In fact, that wouldn't even compile. How come? Because the argument
-to push() must be a real array, not just a reference to such.
+ use v5.14; # needed for implicit deref of array refs by array ops
+
+directive at the top of the file that needs it. That way when somebody
+tries to run the new code under an old perl, rather than getting an error like
+
+ Type of arg 1 to push must be array (not array element) at /tmp/a line 8, near ""betty";"
+ Execution of /tmp/a aborted due to compilation errors.
+
+they'll be politely informed that
+
+ Perl v5.14.0 required--this is only v5.12.3, stopped at /tmp/a line 1.
+ BEGIN failed--compilation aborted at /tmp/a line 1.
=head2 Access and Printing
@@ -194,20 +228,20 @@ using the shell-style for() construct to loop across the outer
set of subscripts.
for $aref ( @AoA ) {
- print "\t [ @$aref ],\n";
+ say "\t [ @$aref ],";
}
If you wanted to keep track of subscripts, you might do this:
for $i ( 0 .. $#AoA ) {
- print "\t elt $i is [ @{$AoA[$i]} ],\n";
+ say "\t elt $i is [ @{$AoA[$i]} ],";
}
or maybe even this. Notice the inner loop.
for $i ( 0 .. $#AoA ) {
for $j ( 0 .. $#{$AoA[$i]} ) {
- print "elt $i $j is $AoA[$i][$j]\n";
+ say "elt $i $j is $AoA[$i][$j]";
}
}
@@ -217,7 +251,7 @@ sometimes is easier to take a temporary on your way through:
for $i ( 0 .. $#AoA ) {
$aref = $AoA[$i];
for $j ( 0 .. $#{$aref} ) {
- print "elt $i $j is $AoA[$i][$j]\n";
+ say "elt $i $j is $AoA[$i][$j]";
}
}
@@ -227,18 +261,65 @@ Hmm... that's still a bit ugly. How about this:
$aref = $AoA[$i];
$n = @$aref - 1;
for $j ( 0 .. $n ) {
- print "elt $i $j is $AoA[$i][$j]\n";
+ say "elt $i $j is $AoA[$i][$j]";
}
}
+When you get tired of writing a custom print for your data structures,
+you might look at the standard L<Dumpvalue> or L<Data::Dumper> modules.
+The former is what the Perl debugger uses, while the latter generates
+parsable Perl code. For example:
+
+ use v5.14; # using the + prototype, new to v5.14
+
+ sub show(+) {
+ require Dumpvalue;
+ state $prettily = new Dumpvalue::
+ tick => q("),
+ compactDump => 1, # comment these two lines out
+ veryCompact => 1, # if you want a bigger dump
+ ;
+ dumpValue $prettily @_;
+ }
+
+ # Assign a list of array references to an array.
+ my @AoA = (
+ [ "fred", "barney" ],
+ [ "george", "jane", "elroy" ],
+ [ "homer", "marge", "bart" ],
+ );
+ push $AoA[0], "wilma", "betty";
+ show @AoA;
+
+will print out:
+
+ 0 0..3 "fred" "barney" "wilma" "betty"
+ 1 0..2 "george" "jane" "elroy"
+ 2 0..2 "homer" "marge" "bart"
+
+Whereas if you comment out the two lines I said you might wish to,
+then it shows it to you this way instead:
+
+ 0 ARRAY(0x8031d0)
+ 0 "fred"
+ 1 "barney"
+ 2 "wilma"
+ 3 "betty"
+ 1 ARRAY(0x803d40)
+ 0 "george"
+ 1 "jane"
+ 2 "elroy"
+ 2 ARRAY(0x803e10)
+ 0 "homer"
+ 1 "marge"
+ 2 "bart"
+
=head2 Slices
If you want to get at a slice (part of a row) in a multidimensional
array, you're going to have to do some fancy subscripting. That's
because while we have a nice synonym for single elements via the
pointer arrow for dereferencing, no such convenience exists for slices.
-(Remember, of course, that you can always write a loop to do a slice
-operation.)
Here's how to do one operation using a loop. We'll assume an @AoA
variable as before.
@@ -251,9 +332,13 @@ variable as before.
That same loop could be replaced with a slice operation:
+ @part = @{$AoA[4]}[7..12];
+
+or spaced out a bit:
+
@part = @{ $AoA[4] } [ 7..12 ];
-but as you might well imagine, this is pretty rough on the reader.
+But as you might well imagine, this can get pretty rough on the reader.
Ah, but what if you wanted a I<two-dimensional slice>, such as having
$x run from 4..8 and $y run from 7 to 12? Hmm... here's the simple way:
@@ -300,4 +385,4 @@ L<perldata>, L<perlref>, L<perldsc>
Tom Christiansen <F<tchrist@perl.com>>
-Last update: Thu Jun 4 16:16:23 MDT 1998
+Last update: Tue Apr 26 18:30:55 MDT 2011