source: for-distributions/trunk/bin/windows/perl/lib/Pod/perllol.pod@ 14489

Last change on this file since 14489 was 14489, checked in by oranfry, 17 years ago

upgrading to perl 5.8

File size: 8.1 KB
Line 
1=head1 NAME
2
3perllol - Manipulating Arrays of Arrays in Perl
4
5=head1 DESCRIPTION
6
7=head2 Declaration and Access of Arrays of Arrays
8
9The simplest thing to build is an array of arrays (sometimes imprecisely
10called a list of lists). It's reasonably easy to understand, and
11almost everything that applies here will also be applicable later
12on with the fancier data structures.
13
14An array of an array is just a regular old array @AoA that you can
15get at with two subscripts, like C<$AoA[3][2]>. Here's a declaration
16of the array:
17
18 # assign to our array, an array of array references
19 @AoA = (
20 [ "fred", "barney" ],
21 [ "george", "jane", "elroy" ],
22 [ "homer", "marge", "bart" ],
23 );
24
25 print $AoA[2][2];
26 bart
27
28Now you should be very careful that the outer bracket type
29is a round one, that is, a parenthesis. That's because you're assigning to
30an @array, so you need parentheses. If you wanted there I<not> to be an @AoA,
31but rather just a reference to it, you could do something more like this:
32
33 # assign a reference to array of array references
34 $ref_to_AoA = [
35 [ "fred", "barney", "pebbles", "bambam", "dino", ],
36 [ "homer", "bart", "marge", "maggie", ],
37 [ "george", "jane", "elroy", "judy", ],
38 ];
39
40 print $ref_to_AoA->[2][2];
41
42Notice that the outer bracket type has changed, and so our access syntax
43has also changed. That's because unlike C, in perl you can't freely
44interchange arrays and references thereto. $ref_to_AoA is a reference to an
45array, whereas @AoA is an array proper. Likewise, C<$AoA[2]> is not an
46array, but an array ref. So how come you can write these:
47
48 $AoA[2][2]
49 $ref_to_AoA->[2][2]
50
51instead of having to write these:
52
53 $AoA[2]->[2]
54 $ref_to_AoA->[2]->[2]
55
56Well, that's because the rule is that on adjacent brackets only (whether
57square or curly), you are free to omit the pointer dereferencing arrow.
58But you cannot do so for the very first one if it's a scalar containing
59a reference, which means that $ref_to_AoA always needs it.
60
61=head2 Growing Your Own
62
63That's all well and good for declaration of a fixed data structure,
64but what if you wanted to add new elements on the fly, or build
65it up entirely from scratch?
66
67First, let's look at reading it in from a file. This is something like
68adding a row at a time. We'll assume that there's a flat file in which
69each line is a row and each word an element. If you're trying to develop an
70@AoA array containing all these, here's the right way to do that:
71
72 while (<>) {
73 @tmp = split;
74 push @AoA, [ @tmp ];
75 }
76
77You might also have loaded that from a function:
78
79 for $i ( 1 .. 10 ) {
80 $AoA[$i] = [ somefunc($i) ];
81 }
82
83Or you might have had a temporary variable sitting around with the
84array in it.
85
86 for $i ( 1 .. 10 ) {
87 @tmp = somefunc($i);
88 $AoA[$i] = [ @tmp ];
89 }
90
91It's very important that you make sure to use the C<[]> array reference
92constructor. That's because this will be very wrong:
93
94 $AoA[$i] = @tmp;
95
96You see, assigning a named array like that to a scalar just counts the
97number of elements in @tmp, which probably isn't what you want.
98
99If you are running under C<use strict>, you'll have to add some
100declarations to make it happy:
101
102 use strict;
103 my(@AoA, @tmp);
104 while (<>) {
105 @tmp = split;
106 push @AoA, [ @tmp ];
107 }
108
109Of course, you don't need the temporary array to have a name at all:
110
111 while (<>) {
112 push @AoA, [ split ];
113 }
114
115You also don't have to use push(). You could just make a direct assignment
116if you knew where you wanted to put it:
117
118 my (@AoA, $i, $line);
119 for $i ( 0 .. 10 ) {
120 $line = <>;
121 $AoA[$i] = [ split ' ', $line ];
122 }
123
124or even just
125
126 my (@AoA, $i);
127 for $i ( 0 .. 10 ) {
128 $AoA[$i] = [ split ' ', <> ];
129 }
130
131You should in general be leery of using functions that could
132potentially return lists in scalar context without explicitly stating
133such. This would be clearer to the casual reader:
134
135 my (@AoA, $i);
136 for $i ( 0 .. 10 ) {
137 $AoA[$i] = [ split ' ', scalar(<>) ];
138 }
139
140If you wanted to have a $ref_to_AoA variable as a reference to an array,
141you'd have to do something like this:
142
143 while (<>) {
144 push @$ref_to_AoA, [ split ];
145 }
146
147Now you can add new rows. What about adding new columns? If you're
148dealing with just matrices, it's often easiest to use simple assignment:
149
150 for $x (1 .. 10) {
151 for $y (1 .. 10) {
152 $AoA[$x][$y] = func($x, $y);
153 }
154 }
155
156 for $x ( 3, 7, 9 ) {
157 $AoA[$x][20] += func2($x);
158 }
159
160It doesn't matter whether those elements are already
161there or not: it'll gladly create them for you, setting
162intervening elements to C<undef> as need be.
163
164If you wanted just to append to a row, you'd have
165to do something a bit funnier looking:
166
167 # add new columns to an existing row
168 push @{ $AoA[0] }, "wilma", "betty";
169
170Notice that I I<couldn't> say just:
171
172 push $AoA[0], "wilma", "betty"; # WRONG!
173
174In fact, that wouldn't even compile. How come? Because the argument
175to push() must be a real array, not just a reference to such.
176
177=head2 Access and Printing
178
179Now it's time to print your data structure out. How
180are you going to do that? Well, if you want only one
181of the elements, it's trivial:
182
183 print $AoA[0][0];
184
185If you want to print the whole thing, though, you can't
186say
187
188 print @AoA; # WRONG
189
190because you'll get just references listed, and perl will never
191automatically dereference things for you. Instead, you have to
192roll yourself a loop or two. This prints the whole structure,
193using the shell-style for() construct to loop across the outer
194set of subscripts.
195
196 for $aref ( @AoA ) {
197 print "\t [ @$aref ],\n";
198 }
199
200If you wanted to keep track of subscripts, you might do this:
201
202 for $i ( 0 .. $#AoA ) {
203 print "\t elt $i is [ @{$AoA[$i]} ],\n";
204 }
205
206or maybe even this. Notice the inner loop.
207
208 for $i ( 0 .. $#AoA ) {
209 for $j ( 0 .. $#{$AoA[$i]} ) {
210 print "elt $i $j is $AoA[$i][$j]\n";
211 }
212 }
213
214As you can see, it's getting a bit complicated. That's why
215sometimes is easier to take a temporary on your way through:
216
217 for $i ( 0 .. $#AoA ) {
218 $aref = $AoA[$i];
219 for $j ( 0 .. $#{$aref} ) {
220 print "elt $i $j is $AoA[$i][$j]\n";
221 }
222 }
223
224Hmm... that's still a bit ugly. How about this:
225
226 for $i ( 0 .. $#AoA ) {
227 $aref = $AoA[$i];
228 $n = @$aref - 1;
229 for $j ( 0 .. $n ) {
230 print "elt $i $j is $AoA[$i][$j]\n";
231 }
232 }
233
234=head2 Slices
235
236If you want to get at a slice (part of a row) in a multidimensional
237array, you're going to have to do some fancy subscripting. That's
238because while we have a nice synonym for single elements via the
239pointer arrow for dereferencing, no such convenience exists for slices.
240(Remember, of course, that you can always write a loop to do a slice
241operation.)
242
243Here's how to do one operation using a loop. We'll assume an @AoA
244variable as before.
245
246 @part = ();
247 $x = 4;
248 for ($y = 7; $y < 13; $y++) {
249 push @part, $AoA[$x][$y];
250 }
251
252That same loop could be replaced with a slice operation:
253
254 @part = @{ $AoA[4] } [ 7..12 ];
255
256but as you might well imagine, this is pretty rough on the reader.
257
258Ah, but what if you wanted a I<two-dimensional slice>, such as having
259$x run from 4..8 and $y run from 7 to 12? Hmm... here's the simple way:
260
261 @newAoA = ();
262 for ($startx = $x = 4; $x <= 8; $x++) {
263 for ($starty = $y = 7; $y <= 12; $y++) {
264 $newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y];
265 }
266 }
267
268We can reduce some of the looping through slices
269
270 for ($x = 4; $x <= 8; $x++) {
271 push @newAoA, [ @{ $AoA[$x] } [ 7..12 ] ];
272 }
273
274If you were into Schwartzian Transforms, you would probably
275have selected map for that
276
277 @newAoA = map { [ @{ $AoA[$_] } [ 7..12 ] ] } 4 .. 8;
278
279Although if your manager accused of seeking job security (or rapid
280insecurity) through inscrutable code, it would be hard to argue. :-)
281If I were you, I'd put that in a function:
282
283 @newAoA = splice_2D( \@AoA, 4 => 8, 7 => 12 );
284 sub splice_2D {
285 my $lrr = shift; # ref to array of array refs!
286 my ($x_lo, $x_hi,
287 $y_lo, $y_hi) = @_;
288
289 return map {
290 [ @{ $lrr->[$_] } [ $y_lo .. $y_hi ] ]
291 } $x_lo .. $x_hi;
292 }
293
294
295=head1 SEE ALSO
296
297perldata(1), perlref(1), perldsc(1)
298
299=head1 AUTHOR
300
301Tom Christiansen <F<[email protected]>>
302
303Last update: Thu Jun 4 16:16:23 MDT 1998
Note: See TracBrowser for help on using the repository browser.