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