Commit | Line | Data |
cb1a09d0 |
1 | =head1 NAME |
4633a7c4 |
2 | |
cb1a09d0 |
3 | perldsc - Perl Data Structures Cookbook |
4633a7c4 |
4 | |
cb1a09d0 |
5 | =head1 DESCRIPTION |
4633a7c4 |
6 | |
7 | The single feature most sorely lacking in the Perl programming language |
8 | prior to its 5.0 release was complex data structures. Even without direct |
9 | language support, some valiant programmers did manage to emulate them, but |
10 | it was hard work and not for the faint of heart. You could occasionally |
19799a22 |
11 | get away with the C<$m{$AoA,$b}> notation borrowed from B<awk> in which the |
12 | keys are actually more like a single concatenated string C<"$AoA$b">, but |
4633a7c4 |
13 | traversal and sorting were difficult. More desperate programmers even |
14 | hacked Perl's internal symbol table directly, a strategy that proved hard |
15 | to develop and maintain--to put it mildly. |
16 | |
17 | The 5.0 release of Perl let us have complex data structures. You |
18 | may now write something like this and all of a sudden, you'd have a array |
19 | with three dimensions! |
20 | |
6ba6f0ec |
21 | my @AoA; |
22 | for my $x (1 .. 10) { |
23 | for my $y (1 .. 10) { |
24 | for my $z (1 .. 10) { |
25 | $AoA[$x][$y][$z] = $x ** $y + $z; |
4633a7c4 |
26 | } |
27 | } |
28 | } |
29 | |
30 | Alas, however simple this may appear, underneath it's a much more |
31 | elaborate construct than meets the eye! |
32 | |
19799a22 |
33 | How do you print it out? Why can't you say just C<print @AoA>? How do |
4633a7c4 |
34 | you sort it? How can you pass it to a function or get one of these back |
35 | from a function? Is is an object? Can you save it to disk to read |
36 | back later? How do you access whole rows or columns of that matrix? Do |
4973169d |
37 | all the values have to be numeric? |
4633a7c4 |
38 | |
39 | As you see, it's quite easy to become confused. While some small portion |
40 | of the blame for this can be attributed to the reference-based |
41 | implementation, it's really more due to a lack of existing documentation with |
42 | examples designed for the beginner. |
43 | |
5f05dabc |
44 | This document is meant to be a detailed but understandable treatment of the |
45 | many different sorts of data structures you might want to develop. It |
46 | should also serve as a cookbook of examples. That way, when you need to |
47 | create one of these complex data structures, you can just pinch, pilfer, or |
48 | purloin a drop-in example from here. |
4633a7c4 |
49 | |
50 | Let's look at each of these possible constructs in detail. There are separate |
28757baa |
51 | sections on each of the following: |
4633a7c4 |
52 | |
53 | =over 5 |
54 | |
55 | =item * arrays of arrays |
56 | |
57 | =item * hashes of arrays |
58 | |
59 | =item * arrays of hashes |
60 | |
61 | =item * hashes of hashes |
62 | |
63 | =item * more elaborate constructs |
64 | |
4633a7c4 |
65 | =back |
66 | |
5a964f20 |
67 | But for now, let's look at general issues common to all |
68 | these types of data structures. |
4633a7c4 |
69 | |
70 | =head1 REFERENCES |
71 | |
72 | The most important thing to understand about all data structures in Perl |
73 | -- including multidimensional arrays--is that even though they might |
74 | appear otherwise, Perl C<@ARRAY>s and C<%HASH>es are all internally |
5f05dabc |
75 | one-dimensional. They can hold only scalar values (meaning a string, |
4633a7c4 |
76 | number, or a reference). They cannot directly contain other arrays or |
77 | hashes, but instead contain I<references> to other arrays or hashes. |
78 | |
5f05dabc |
79 | You can't use a reference to a array or hash in quite the same way that you |
80 | would a real array or hash. For C or C++ programmers unused to |
81 | distinguishing between arrays and pointers to the same, this can be |
82 | confusing. If so, just think of it as the difference between a structure |
83 | and a pointer to a structure. |
4633a7c4 |
84 | |
85 | You can (and should) read more about references in the perlref(1) man |
86 | page. Briefly, references are rather like pointers that know what they |
87 | point to. (Objects are also a kind of reference, but we won't be needing |
4973169d |
88 | them right away--if ever.) This means that when you have something which |
89 | looks to you like an access to a two-or-more-dimensional array and/or hash, |
90 | what's really going on is that the base type is |
4633a7c4 |
91 | merely a one-dimensional entity that contains references to the next |
92 | level. It's just that you can I<use> it as though it were a |
93 | two-dimensional one. This is actually the way almost all C |
94 | multidimensional arrays work as well. |
95 | |
19799a22 |
96 | $array[7][12] # array of arrays |
97 | $array[7]{string} # array of hashes |
4633a7c4 |
98 | $hash{string}[7] # hash of arrays |
99 | $hash{string}{'another string'} # hash of hashes |
100 | |
5f05dabc |
101 | Now, because the top level contains only references, if you try to print |
4633a7c4 |
102 | out your array in with a simple print() function, you'll get something |
103 | that doesn't look very nice, like this: |
104 | |
6ba6f0ec |
105 | my @AoA = ( |
106 | [2, 3, ], |
107 | [4, 5, 7], |
108 | [0, ], |
109 | ); |
19799a22 |
110 | print $AoA[1][2]; |
4633a7c4 |
111 | 7 |
19799a22 |
112 | print @AoA; |
4633a7c4 |
113 | ARRAY(0x83c38)ARRAY(0x8b194)ARRAY(0x8b1d0) |
114 | |
115 | |
116 | That's because Perl doesn't (ever) implicitly dereference your variables. |
117 | If you want to get at the thing a reference is referring to, then you have |
118 | to do this yourself using either prefix typing indicators, like |
119 | C<${$blah}>, C<@{$blah}>, C<@{$blah[$i]}>, or else postfix pointer arrows, |
120 | like C<$a-E<gt>[3]>, C<$h-E<gt>{fred}>, or even C<$ob-E<gt>method()-E<gt>[3]>. |
121 | |
122 | =head1 COMMON MISTAKES |
123 | |
124 | The two most common mistakes made in constructing something like |
125 | an array of arrays is either accidentally counting the number of |
126 | elements or else taking a reference to the same memory location |
127 | repeatedly. Here's the case where you just get the count instead |
128 | of a nested array: |
129 | |
6ba6f0ec |
130 | my @AoA; |
131 | for my $i (1..10) { |
132 | my @array = somefunc($i); |
133 | $AoA[$i] = @array; # WRONG! |
4973169d |
134 | } |
4633a7c4 |
135 | |
19799a22 |
136 | That's just the simple case of assigning an array to a scalar and getting |
4633a7c4 |
137 | its element count. If that's what you really and truly want, then you |
138 | might do well to consider being a tad more explicit about it, like this: |
139 | |
6ba6f0ec |
140 | my @counts; |
141 | for my $i (1..10) { |
142 | my @array = somefunc($i); |
143 | $counts[$i] = scalar @array; |
4973169d |
144 | } |
4633a7c4 |
145 | |
6ba6f0ec |
146 | Here's the right way to do the reference C<@array>: |
4633a7c4 |
147 | |
6ba6f0ec |
148 | my @AoA |
149 | for my $i (1..10) { |
150 | my @array = somefunc($i); |
151 | $AoA[$i] = [ @array ]; |
4973169d |
152 | } |
4633a7c4 |
153 | |
154 | The square brackets make a reference to a new array with a I<copy> |
6ba6f0ec |
155 | of what's in C<@array>. |
4633a7c4 |
156 | |
157 | Note that this will produce something similar, but it's |
158 | much harder to read: |
159 | |
6ba6f0ec |
160 | my @AoA; |
161 | for my $i (1..10) { |
162 | my @array = somefunc($i); |
163 | @{ $AoA[$i] } = @array; |
4973169d |
164 | } |
4633a7c4 |
165 | |
166 | Is it the same? Well, maybe so--and maybe not. The subtle difference |
167 | is that when you assign something in square brackets, you know for sure |
168 | it's always a brand new reference with a new I<copy> of the data. |
6ba6f0ec |
169 | Something else could be going on in this new case with the C<@{ $AoA[$i]} }> |
4633a7c4 |
170 | dereference on the left-hand-side of the assignment. It all depends on |
19799a22 |
171 | whether C<$AoA[$i]> had been undefined to start with, or whether it |
172 | already contained a reference. If you had already populated @AoA with |
4633a7c4 |
173 | references, as in |
174 | |
19799a22 |
175 | $AoA[3] = \@another_array; |
4633a7c4 |
176 | |
177 | Then the assignment with the indirection on the left-hand-side would |
178 | use the existing reference that was already there: |
179 | |
6ba6f0ec |
180 | @{ $AoA[3] } = @array; |
4633a7c4 |
181 | |
182 | Of course, this I<would> have the "interesting" effect of clobbering |
19799a22 |
183 | @another_array. (Have you ever noticed how when a programmer says |
4633a7c4 |
184 | something is "interesting", that rather than meaning "intriguing", |
185 | they're disturbingly more apt to mean that it's "annoying", |
186 | "difficult", or both? :-) |
187 | |
5f05dabc |
188 | So just remember always to use the array or hash constructors with C<[]> |
4633a7c4 |
189 | or C<{}>, and you'll be fine, although it's not always optimally |
4973169d |
190 | efficient. |
4633a7c4 |
191 | |
192 | Surprisingly, the following dangerous-looking construct will |
193 | actually work out fine: |
194 | |
6ba6f0ec |
195 | my @AoA; |
196 | for my $i (1..10) { |
197 | my @array = somefunc($i); |
198 | $AoA[$i] = \@array; |
4973169d |
199 | } |
4633a7c4 |
200 | |
201 | That's because my() is more of a run-time statement than it is a |
202 | compile-time declaration I<per se>. This means that the my() variable is |
203 | remade afresh each time through the loop. So even though it I<looks> as |
204 | though you stored the same variable reference each time, you actually did |
205 | not! This is a subtle distinction that can produce more efficient code at |
206 | the risk of misleading all but the most experienced of programmers. So I |
207 | usually advise against teaching it to beginners. In fact, except for |
208 | passing arguments to functions, I seldom like to see the gimme-a-reference |
209 | operator (backslash) used much at all in code. Instead, I advise |
210 | beginners that they (and most of the rest of us) should try to use the |
211 | much more easily understood constructors C<[]> and C<{}> instead of |
212 | relying upon lexical (or dynamic) scoping and hidden reference-counting to |
213 | do the right thing behind the scenes. |
214 | |
215 | In summary: |
216 | |
6ba6f0ec |
217 | $AoA[$i] = [ @array ]; # usually best |
218 | $AoA[$i] = \@array; # perilous; just how my() is that array? |
219 | @{ $AoA[$i] } = @array; # way too tricky for most programmers |
4633a7c4 |
220 | |
221 | |
4973169d |
222 | =head1 CAVEAT ON PRECEDENCE |
4633a7c4 |
223 | |
6ba6f0ec |
224 | Speaking of things like C<@{ $AoA[$i] }>, the following are actually the |
4633a7c4 |
225 | same thing: |
226 | |
19799a22 |
227 | $aref->[2][2] # clear |
228 | $$aref[2][2] # confusing |
4633a7c4 |
229 | |
230 | That's because Perl's precedence rules on its five prefix dereferencers |
231 | (which look like someone swearing: C<$ @ * % &>) make them bind more |
232 | tightly than the postfix subscripting brackets or braces! This will no |
233 | doubt come as a great shock to the C or C++ programmer, who is quite |
234 | accustomed to using C<*a[i]> to mean what's pointed to by the I<i'th> |
235 | element of C<a>. That is, they first take the subscript, and only then |
236 | dereference the thing at that subscript. That's fine in C, but this isn't C. |
237 | |
19799a22 |
238 | The seemingly equivalent construct in Perl, C<$$aref[$i]> first does |
239 | the deref of $aref, making it take $aref as a reference to an |
4633a7c4 |
240 | array, and then dereference that, and finally tell you the I<i'th> value |
19799a22 |
241 | of the array pointed to by $AoA. If you wanted the C notion, you'd have to |
242 | write C<${$AoA[$i]}> to force the C<$AoA[$i]> to get evaluated first |
4633a7c4 |
243 | before the leading C<$> dereferencer. |
244 | |
245 | =head1 WHY YOU SHOULD ALWAYS C<use strict> |
246 | |
247 | If this is starting to sound scarier than it's worth, relax. Perl has |
248 | some features to help you avoid its most common pitfalls. The best |
249 | way to avoid getting confused is to start every program like this: |
250 | |
251 | #!/usr/bin/perl -w |
252 | use strict; |
253 | |
254 | This way, you'll be forced to declare all your variables with my() and |
255 | also disallow accidental "symbolic dereferencing". Therefore if you'd done |
256 | this: |
257 | |
19799a22 |
258 | my $aref = [ |
6ba6f0ec |
259 | [ 'fred', 'barney', 'pebbles', 'bambam', 'dino', ], |
260 | [ 'homer', 'bart', 'marge', 'maggie', ], |
261 | [ 'george', 'jane', 'elroy', 'judy', ], |
4633a7c4 |
262 | ]; |
263 | |
19799a22 |
264 | print $aref[2][2]; |
4633a7c4 |
265 | |
266 | The compiler would immediately flag that as an error I<at compile time>, |
19799a22 |
267 | because you were accidentally accessing C<@aref>, an undeclared |
5f05dabc |
268 | variable, and it would thereby remind you to write instead: |
4633a7c4 |
269 | |
19799a22 |
270 | print $aref->[2][2] |
4633a7c4 |
271 | |
272 | =head1 DEBUGGING |
273 | |
a6006777 |
274 | Before version 5.002, the standard Perl debugger didn't do a very nice job of |
275 | printing out complex data structures. With 5.002 or above, the |
4973169d |
276 | debugger includes several new features, including command line editing as |
277 | well as the C<x> command to dump out complex data structures. For |
19799a22 |
278 | example, given the assignment to $AoA above, here's the debugger output: |
4633a7c4 |
279 | |
19799a22 |
280 | DB<1> x $AoA |
281 | $AoA = ARRAY(0x13b5a0) |
4633a7c4 |
282 | 0 ARRAY(0x1f0a24) |
283 | 0 'fred' |
284 | 1 'barney' |
285 | 2 'pebbles' |
286 | 3 'bambam' |
287 | 4 'dino' |
288 | 1 ARRAY(0x13b558) |
289 | 0 'homer' |
290 | 1 'bart' |
291 | 2 'marge' |
292 | 3 'maggie' |
293 | 2 ARRAY(0x13b540) |
294 | 0 'george' |
295 | 1 'jane' |
5f05dabc |
296 | 2 'elroy' |
4633a7c4 |
297 | 3 'judy' |
298 | |
cb1a09d0 |
299 | =head1 CODE EXAMPLES |
300 | |
54310121 |
301 | Presented with little comment (these will get their own manpages someday) |
4973169d |
302 | here are short code examples illustrating access of various |
cb1a09d0 |
303 | types of data structures. |
304 | |
19799a22 |
305 | =head1 ARRAYS OF ARRAYS |
cb1a09d0 |
306 | |
19799a22 |
307 | =head2 Declaration of a ARRAY OF ARRAYS |
cb1a09d0 |
308 | |
6ba6f0ec |
309 | my @AoA = ( |
310 | [ 'fred', 'barney' ], |
311 | [ 'george', 'jane', 'elroy' ], |
312 | [ 'homer', 'marge', 'bart' ], |
cb1a09d0 |
313 | ); |
314 | |
19799a22 |
315 | =head2 Generation of a ARRAY OF ARRAYS |
cb1a09d0 |
316 | |
317 | # reading from file |
6ba6f0ec |
318 | my @AoA; |
cb1a09d0 |
319 | while ( <> ) { |
19799a22 |
320 | push @AoA, [ split ]; |
4973169d |
321 | } |
cb1a09d0 |
322 | |
323 | # calling a function |
6ba6f0ec |
324 | my @AoA; |
325 | foreach my $i ( 1 .. 10 ) { |
19799a22 |
326 | $AoA[$i] = [ somefunc($i) ]; |
4973169d |
327 | } |
cb1a09d0 |
328 | |
329 | # using temp vars |
6ba6f0ec |
330 | my @AoA; |
331 | foreach my $i ( 1 .. 10 ) { |
332 | my @tmp = somefunc($i); |
333 | $AoA[$i] = [ @tmp ]; |
4973169d |
334 | } |
cb1a09d0 |
335 | |
336 | # add to an existing row |
6ba6f0ec |
337 | push @{ $AoA[0] }, 'wilma', 'betty'; |
cb1a09d0 |
338 | |
19799a22 |
339 | =head2 Access and Printing of a ARRAY OF ARRAYS |
cb1a09d0 |
340 | |
6ba6f0ec |
341 | my @AoA; |
342 | |
cb1a09d0 |
343 | # one element |
6ba6f0ec |
344 | $AoA[0][0] = 'Fred'; |
cb1a09d0 |
345 | |
346 | # another element |
19799a22 |
347 | $AoA[1][1] =~ s/(\w)/\u$1/; |
cb1a09d0 |
348 | |
349 | # print the whole thing with refs |
6ba6f0ec |
350 | foreach my $aref ( @AoA ) { |
cb1a09d0 |
351 | print "\t [ @$aref ],\n"; |
4973169d |
352 | } |
cb1a09d0 |
353 | |
354 | # print the whole thing with indices |
6ba6f0ec |
355 | foreach my $i ( 0 .. $#AoA ) { |
356 | print "\t [ @{ $AoA[$i] } ],\n"; |
4973169d |
357 | } |
cb1a09d0 |
358 | |
359 | # print the whole thing one at a time |
6ba6f0ec |
360 | foreach my $i ( 0 .. $#AoA ) { |
361 | foreach my $j ( 0 .. $#{ $AoA[$i] } ) { |
362 | print "element $i $j is $AoA[$i][$j]\n"; |
cb1a09d0 |
363 | } |
4973169d |
364 | } |
cb1a09d0 |
365 | |
19799a22 |
366 | =head1 HASHES OF ARRAYS |
cb1a09d0 |
367 | |
19799a22 |
368 | =head2 Declaration of a HASH OF ARRAYS |
cb1a09d0 |
369 | |
6ba6f0ec |
370 | my %HoA = ( |
371 | flintstones => [ 'fred', 'barney' ], |
372 | jetsons => [ 'george', 'jane', 'elroy' ], |
373 | simpsons => [ 'homer', 'marge', 'bart' ], |
cb1a09d0 |
374 | ); |
375 | |
19799a22 |
376 | =head2 Generation of a HASH OF ARRAYS |
cb1a09d0 |
377 | |
378 | # reading from file |
379 | # flintstones: fred barney wilma dino |
6ba6f0ec |
380 | my %HoA; |
cb1a09d0 |
381 | while ( <> ) { |
6ba6f0ec |
382 | next unless s/^([^:]*):\s*//; |
19799a22 |
383 | $HoA{$1} = [ split ]; |
4973169d |
384 | } |
cb1a09d0 |
385 | |
386 | # reading from file; more temps |
387 | # flintstones: fred barney wilma dino |
6ba6f0ec |
388 | my %HoA; |
389 | while ( my $line = <> ) { |
390 | my ($who, $rest) = split /:\s*/, $line, 2; |
391 | my @fields = split ' ', $rest; |
392 | $HoA{$who} = [ @fields ]; |
4973169d |
393 | } |
cb1a09d0 |
394 | |
395 | # calling a function that returns a list |
6ba6f0ec |
396 | my %HoA; |
397 | foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { |
19799a22 |
398 | $HoA{$group} = [ get_family($group) ]; |
4973169d |
399 | } |
cb1a09d0 |
400 | |
401 | # likewise, but using temps |
6ba6f0ec |
402 | my %HoA; |
403 | foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { |
404 | my @members = get_family($group); |
405 | $HoA{$group} = [ @members ]; |
4973169d |
406 | } |
cb1a09d0 |
407 | |
408 | # append new members to an existing family |
6ba6f0ec |
409 | push @{ $HoA{flintstones} }, 'wilma', 'betty'; |
cb1a09d0 |
410 | |
19799a22 |
411 | =head2 Access and Printing of a HASH OF ARRAYS |
cb1a09d0 |
412 | |
6ba6f0ec |
413 | my %HoA; |
414 | |
cb1a09d0 |
415 | # one element |
6ba6f0ec |
416 | $HoA{flintstones}[0] = 'Fred'; |
cb1a09d0 |
417 | |
418 | # another element |
19799a22 |
419 | $HoA{simpsons}[1] =~ s/(\w)/\u$1/; |
cb1a09d0 |
420 | |
421 | # print the whole thing |
6ba6f0ec |
422 | foreach my $family ( keys %HoA ) { |
423 | print "$family: @{ $HoA{$family} }\n"; |
4973169d |
424 | } |
cb1a09d0 |
425 | |
426 | # print the whole thing with indices |
6ba6f0ec |
427 | foreach my $family ( keys %HoA ) { |
428 | print 'family: '; |
429 | foreach my $i ( 0 .. $#{ $HoA{$family} } ) { |
19799a22 |
430 | print " $i = $HoA{$family}[$i]"; |
cb1a09d0 |
431 | } |
432 | print "\n"; |
4973169d |
433 | } |
cb1a09d0 |
434 | |
435 | # print the whole thing sorted by number of members |
6ba6f0ec |
436 | sub num_members { |
437 | @{ $HoA{$b} } <=> @{ $HoA{$a} } |
438 | } |
439 | foreach my $family ( sort num_members keys %HoA ) { |
19799a22 |
440 | print "$family: @{ $HoA{$family} }\n" |
4973169d |
441 | } |
cb1a09d0 |
442 | |
443 | # print the whole thing sorted by number of members and name |
6ba6f0ec |
444 | sub members_and_name { |
445 | @{ $HoA{$b} } <=> @{ $HoA{$a} } |
446 | || |
447 | $a cmp $b |
448 | } |
449 | foreach my $family ( sort members_and_name keys %HoA ) { |
19799a22 |
450 | print "$family: ", join(", ", sort @{ $HoA{$family} }), "\n"; |
4973169d |
451 | } |
cb1a09d0 |
452 | |
19799a22 |
453 | =head1 ARRAYS OF HASHES |
cb1a09d0 |
454 | |
19799a22 |
455 | =head2 Declaration of a ARRAY OF HASHES |
cb1a09d0 |
456 | |
6ba6f0ec |
457 | my @AoH = ( |
cb1a09d0 |
458 | { |
6ba6f0ec |
459 | Lead => 'fred', |
460 | Friend => 'barney', |
cb1a09d0 |
461 | }, |
462 | { |
6ba6f0ec |
463 | Lead => 'george', |
464 | Wife => 'jane', |
465 | Son => 'elroy', |
cb1a09d0 |
466 | }, |
467 | { |
6ba6f0ec |
468 | Lead => 'homer', |
469 | Wife => 'marge', |
470 | Son => 'bart', |
cb1a09d0 |
471 | } |
472 | ); |
473 | |
19799a22 |
474 | =head2 Generation of a ARRAY OF HASHES |
cb1a09d0 |
475 | |
476 | # reading from file |
477 | # format: LEAD=fred FRIEND=barney |
6ba6f0ec |
478 | my @AoH; |
cb1a09d0 |
479 | while ( <> ) { |
6ba6f0ec |
480 | my $rec = {}; |
481 | foreach my $field ( split ) { |
482 | my($key, $value) = split /=/, $field; |
483 | $rec->{$key} = $value; |
cb1a09d0 |
484 | } |
19799a22 |
485 | push @AoH, $rec; |
4973169d |
486 | } |
cb1a09d0 |
487 | |
488 | |
489 | # reading from file |
490 | # format: LEAD=fred FRIEND=barney |
491 | # no temp |
6ba6f0ec |
492 | my @AoH; |
cb1a09d0 |
493 | while ( <> ) { |
19799a22 |
494 | push @AoH, { split /[\s+=]/ }; |
4973169d |
495 | } |
cb1a09d0 |
496 | |
19799a22 |
497 | # calling a function that returns a key/value pair list, like |
6ba6f0ec |
498 | # lead => 'fred', daughter => 'pebbles' |
499 | my @AoH; |
500 | while ( my %fields = getnextpairset() ) { |
19799a22 |
501 | push @AoH, { %fields }; |
4973169d |
502 | } |
cb1a09d0 |
503 | |
504 | # likewise, but using no temp vars |
6ba6f0ec |
505 | my @AoH; |
cb1a09d0 |
506 | while (<>) { |
19799a22 |
507 | push @AoH, { parsepairs($_) }; |
4973169d |
508 | } |
cb1a09d0 |
509 | |
510 | # add key/value to an element |
6ba6f0ec |
511 | $AoH[0]{pet} = 'dino'; |
19799a22 |
512 | $AoH[2]{pet} = "santa's little helper"; |
cb1a09d0 |
513 | |
19799a22 |
514 | =head2 Access and Printing of a ARRAY OF HASHES |
cb1a09d0 |
515 | |
6ba6f0ec |
516 | my @AoH; |
517 | |
cb1a09d0 |
518 | # one element |
6ba6f0ec |
519 | $AoH[0]{lead} = 'fred'; |
cb1a09d0 |
520 | |
521 | # another element |
19799a22 |
522 | $AoH[1]{lead} =~ s/(\w)/\u$1/; |
cb1a09d0 |
523 | |
524 | # print the whole thing with refs |
6ba6f0ec |
525 | foreach my $href ( @AoH ) { |
526 | print '{ '; |
527 | foreach my $role ( keys %$href ) { |
528 | print "$role = $href->{$role} "; |
cb1a09d0 |
529 | } |
530 | print "}\n"; |
4973169d |
531 | } |
cb1a09d0 |
532 | |
533 | # print the whole thing with indices |
6ba6f0ec |
534 | foreach my $i ( 0 .. $#AoH ) { |
cb1a09d0 |
535 | print "$i is { "; |
6ba6f0ec |
536 | foreach my $role ( keys %{ $AoH[$i] } ) { |
537 | print "$role = $AoH[$i]{$role} "; |
cb1a09d0 |
538 | } |
539 | print "}\n"; |
4973169d |
540 | } |
cb1a09d0 |
541 | |
542 | # print the whole thing one at a time |
6ba6f0ec |
543 | foreach my $i ( 0 .. $#AoH ) { |
544 | foreach my $role ( keys %{ $AoH[$i] } ) { |
545 | print "element $i $role is $AoH[$i]{$role}\n"; |
cb1a09d0 |
546 | } |
4973169d |
547 | } |
cb1a09d0 |
548 | |
549 | =head1 HASHES OF HASHES |
550 | |
551 | =head2 Declaration of a HASH OF HASHES |
552 | |
6ba6f0ec |
553 | my %HoH = ( |
28757baa |
554 | flintstones => { |
6ba6f0ec |
555 | lead => 'fred', |
556 | pal => 'barney', |
cb1a09d0 |
557 | }, |
28757baa |
558 | jetsons => { |
6ba6f0ec |
559 | lead => 'george', |
560 | wife => 'jane', |
561 | 'his boy' => 'elroy', |
4973169d |
562 | }, |
28757baa |
563 | simpsons => { |
6ba6f0ec |
564 | lead => 'homer', |
565 | wife => 'marge', |
566 | kid => 'bart', |
4973169d |
567 | }, |
568 | ); |
cb1a09d0 |
569 | |
570 | =head2 Generation of a HASH OF HASHES |
571 | |
572 | # reading from file |
573 | # flintstones: lead=fred pal=barney wife=wilma pet=dino |
6ba6f0ec |
574 | my %HoH; |
cb1a09d0 |
575 | while ( <> ) { |
6ba6f0ec |
576 | next unless s/^([^:]*):\s*//; |
577 | my $who = $1; |
578 | for my $field ( split ) { |
579 | my($key, $value) = split /=/, $field; |
cb1a09d0 |
580 | $HoH{$who}{$key} = $value; |
581 | } |
582 | |
583 | |
584 | # reading from file; more temps |
6ba6f0ec |
585 | my %HoH; |
cb1a09d0 |
586 | while ( <> ) { |
6ba6f0ec |
587 | next unless s/^([^:]*):\s*//; |
588 | my $who = $1; |
589 | my $rec = {}; |
cb1a09d0 |
590 | $HoH{$who} = $rec; |
6ba6f0ec |
591 | foreach my $field ( split ) { |
592 | my($key, $value) = split /=/, $field; |
593 | $rec->{$key} = $value; |
cb1a09d0 |
594 | } |
4973169d |
595 | } |
cb1a09d0 |
596 | |
cb1a09d0 |
597 | # calling a function that returns a key,value hash |
6ba6f0ec |
598 | my %HoH; |
599 | foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { |
cb1a09d0 |
600 | $HoH{$group} = { get_family($group) }; |
4973169d |
601 | } |
cb1a09d0 |
602 | |
603 | # likewise, but using temps |
6ba6f0ec |
604 | my %HoH; |
605 | foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { |
606 | my %members = get_family($group); |
cb1a09d0 |
607 | $HoH{$group} = { %members }; |
4973169d |
608 | } |
cb1a09d0 |
609 | |
610 | # append new members to an existing family |
6ba6f0ec |
611 | my %HoH; |
612 | my %new_folks = ( |
613 | wife => 'wilma', |
614 | pet => 'dino', |
cb1a09d0 |
615 | ); |
4973169d |
616 | |
6ba6f0ec |
617 | foreach my $what (keys %new_folks) { |
cb1a09d0 |
618 | $HoH{flintstones}{$what} = $new_folks{$what}; |
4973169d |
619 | } |
cb1a09d0 |
620 | |
621 | =head2 Access and Printing of a HASH OF HASHES |
622 | |
6ba6f0ec |
623 | %HoH; |
624 | |
cb1a09d0 |
625 | # one element |
6ba6f0ec |
626 | $HoH{flintstones}{wife} = 'wilma'; |
cb1a09d0 |
627 | |
628 | # another element |
629 | $HoH{simpsons}{lead} =~ s/(\w)/\u$1/; |
630 | |
631 | # print the whole thing |
6ba6f0ec |
632 | foreach my $family ( keys %HoH ) { |
1fef88e7 |
633 | print "$family: { "; |
6ba6f0ec |
634 | foreach my $role ( keys %{ $HoH{$family} } ) { |
635 | print "$role = $HoH{$family}{$role} "; |
cb1a09d0 |
636 | } |
637 | print "}\n"; |
4973169d |
638 | } |
cb1a09d0 |
639 | |
640 | # print the whole thing somewhat sorted |
6ba6f0ec |
641 | foreach my $family ( sort keys %HoH ) { |
1fef88e7 |
642 | print "$family: { "; |
6ba6f0ec |
643 | foreach my $role ( sort keys %{ $HoH{$family} } ) { |
644 | print "$role = $HoH{$family}{$role} "; |
cb1a09d0 |
645 | } |
646 | print "}\n"; |
4973169d |
647 | } |
cb1a09d0 |
648 | |
cb1a09d0 |
649 | # print the whole thing sorted by number of members |
6ba6f0ec |
650 | sub num_members { |
651 | keys %{ $HoH{$b} } <=> keys %{ $HoH{$a} } |
652 | } |
653 | foreach my $family ( sort num_members keys %HoH ) { |
1fef88e7 |
654 | print "$family: { "; |
6ba6f0ec |
655 | foreach my $role ( sort keys %{ $HoH{$family} } ) { |
656 | print "$role = $HoH{$family}{$role} "; |
cb1a09d0 |
657 | } |
658 | print "}\n"; |
4973169d |
659 | } |
cb1a09d0 |
660 | |
661 | # establish a sort order (rank) for each role |
6ba6f0ec |
662 | my %rank; |
663 | my $i = 0; |
664 | foreach ( qw(lead wife son daughter pal pet) ) { |
665 | $rank{$_} = ++$i; |
666 | } |
cb1a09d0 |
667 | |
668 | # now print the whole thing sorted by number of members |
6ba6f0ec |
669 | sub num_members { |
670 | keys %{ $HoH{$b} } <=> keys %{ $HoH{$a} } |
671 | } |
672 | sub rank { |
673 | $rank{$a} <=> $rank{$b} |
674 | } |
675 | |
676 | foreach my $family ( sort num_members keys %HoH ) { |
1fef88e7 |
677 | print "$family: { "; |
cb1a09d0 |
678 | # and print these according to rank order |
6ba6f0ec |
679 | foreach my $role ( sort rank keys %{ $HoH{$family} } ) { |
680 | print "$role = $HoH{$family}{$role} "; |
cb1a09d0 |
681 | } |
682 | print "}\n"; |
4973169d |
683 | } |
cb1a09d0 |
684 | |
685 | |
686 | =head1 MORE ELABORATE RECORDS |
687 | |
688 | =head2 Declaration of MORE ELABORATE RECORDS |
689 | |
690 | Here's a sample showing how to create and use a record whose fields are of |
691 | many different sorts: |
692 | |
6ba6f0ec |
693 | my $rec = { |
4973169d |
694 | TEXT => $string, |
695 | SEQUENCE => [ @old_values ], |
696 | LOOKUP => { %some_table }, |
697 | THATCODE => \&some_function, |
698 | THISCODE => sub { $_[0] ** $_[1] }, |
699 | HANDLE => \*STDOUT, |
cb1a09d0 |
700 | }; |
701 | |
4973169d |
702 | print $rec->{TEXT}; |
cb1a09d0 |
703 | |
6ba6f0ec |
704 | print $rec->{SEQUENCE}->[0]; |
705 | my $last = pop @{ $rec->{SEQUENCE} }; |
cb1a09d0 |
706 | |
6ba6f0ec |
707 | print $rec->{LOOKUP}->{key}; |
708 | my($first_k, $first_v) = each %{ $rec->{LOOKUP} }; |
cb1a09d0 |
709 | |
6ba6f0ec |
710 | my $answer = $rec->{THATCODE}->($arg); |
711 | my $result = $rec->{THISCODE}->($arg1, $arg2); |
cb1a09d0 |
712 | |
713 | # careful of extra block braces on fh ref |
4973169d |
714 | print { $rec->{HANDLE} } "a string\n"; |
cb1a09d0 |
715 | |
716 | use FileHandle; |
4973169d |
717 | $rec->{HANDLE}->autoflush(1); |
718 | $rec->{HANDLE}->print(" a string\n"); |
cb1a09d0 |
719 | |
720 | =head2 Declaration of a HASH OF COMPLEX RECORDS |
721 | |
6ba6f0ec |
722 | my %TV = ( |
28757baa |
723 | flintstones => { |
6ba6f0ec |
724 | series => 'flintstones', |
4973169d |
725 | nights => [ qw(monday thursday friday) ], |
cb1a09d0 |
726 | members => [ |
6ba6f0ec |
727 | { name => 'fred', role => 'lead', age => 36, }, |
728 | { name => 'wilma', role => 'wife', age => 31, }, |
729 | { name => 'pebbles', role => 'kid', age => 4, }, |
cb1a09d0 |
730 | ], |
731 | }, |
732 | |
28757baa |
733 | jetsons => { |
6ba6f0ec |
734 | series => 'jetsons', |
4973169d |
735 | nights => [ qw(wednesday saturday) ], |
cb1a09d0 |
736 | members => [ |
6ba6f0ec |
737 | { name => 'george", role => 'lead', age => 41, }, |
738 | { name => 'jane", role => 'wife', age => 39, }, |
739 | { name => 'elroy", role => 'kid', age => 9, }, |
cb1a09d0 |
740 | ], |
741 | }, |
742 | |
28757baa |
743 | simpsons => { |
6ba6f0ec |
744 | series => 'simpsons', |
4973169d |
745 | nights => [ qw(monday) ], |
cb1a09d0 |
746 | members => [ |
6ba6f0ec |
747 | { name => 'homer', role => 'lead', age => 34, }, |
748 | { name => 'marge', role => 'wife', age => 37, }, |
749 | { name => 'bart', role => 'kid', age => 11, }, |
cb1a09d0 |
750 | ], |
751 | }, |
752 | ); |
753 | |
754 | =head2 Generation of a HASH OF COMPLEX RECORDS |
755 | |
6ba6f0ec |
756 | Here's a piece by piece build up of a hash of complex records. We'll |
757 | read in a file that has our data in it. |
cb1a09d0 |
758 | |
6ba6f0ec |
759 | my %TV = (); |
760 | my $rec = {}; |
761 | $rec->{series} = 'flintstones'; |
cb1a09d0 |
762 | $rec->{nights} = [ find_days() ]; |
763 | |
6ba6f0ec |
764 | my @members = (); |
cb1a09d0 |
765 | # assume this file in field=value syntax |
6ba6f0ec |
766 | while ( <> ) { |
767 | my %fields = split /[\s=]+/, $_; |
cb1a09d0 |
768 | push @members, { %fields }; |
769 | } |
770 | $rec->{members} = [ @members ]; |
771 | |
772 | # now remember the whole thing |
773 | $TV{ $rec->{series} } = $rec; |
774 | |
6ba6f0ec |
775 | Now, you might want to make interesting extra fields that |
776 | include pointers back into the same data structure so if |
777 | change one piece, it changes everywhere, like for example |
778 | if you wanted a 'kids' field that was a reference |
779 | to an array of the kids' records without having duplicate |
780 | records and thus update problems. |
781 | |
782 | foreach my $family ( keys %TV ) { |
783 | my $rec = $TV{$family}; # $rec points to $TV{$family} |
784 | my @kids = (); |
785 | foreach my $person ( @{ $rec->{members} } ) { |
786 | if ( $person->{role} =~ /kid|son|daughter/ ) { |
cb1a09d0 |
787 | push @kids, $person; |
788 | } |
789 | } |
790 | # REMEMBER: $rec and $TV{$family} point to same data!! |
791 | $rec->{kids} = [ @kids ]; |
792 | } |
793 | |
6ba6f0ec |
794 | You copied the array, but the array itself contains pointers |
795 | to uncopied objects. This means that if you make bart get |
796 | older via |
cb1a09d0 |
797 | |
798 | $TV{simpsons}{kids}[0]{age}++; |
799 | |
6ba6f0ec |
800 | Then this would also change in C<$TV{simpsons}{members}[2]{age}> |
801 | because C<$TV{simpsons}{kids}[0]> and C<$TV{simpsons}{members}[2]> |
802 | both point to the same underlying anonymous hash table. |
cb1a09d0 |
803 | |
804 | # print the whole thing |
6ba6f0ec |
805 | foreach my $family ( keys %TV ) { |
806 | print "the $family is on during @{ $TV{$family}{nights} }\n", |
807 | "its members are:\n"; |
808 | |
809 | foraech my $who ( @{ $TV{$family}{members} } ) { |
cb1a09d0 |
810 | print " $who->{name} ($who->{role}), age $who->{age}\n"; |
811 | } |
6ba6f0ec |
812 | |
813 | print "it turns out that $TV{$family}{lead} has ", |
814 | scalar ( @{ $TV{$family}{kids} } ), |
815 | ' kids named ', |
816 | join( |
817 | ', ', |
818 | map { $_->{name} } @{ $TV{$family}{kids} } |
819 | ), |
820 | "\n"; |
cb1a09d0 |
821 | } |
822 | |
c07a80fd |
823 | =head1 Database Ties |
824 | |
825 | You cannot easily tie a multilevel data structure (such as a hash of |
826 | hashes) to a dbm file. The first problem is that all but GDBM and |
827 | Berkeley DB have size limitations, but beyond that, you also have problems |
828 | with how references are to be represented on disk. One experimental |
5f05dabc |
829 | module that does partially attempt to address this need is the MLDBM |
f102b883 |
830 | module. Check your nearest CPAN site as described in L<perlmodlib> for |
c07a80fd |
831 | source code to MLDBM. |
832 | |
4633a7c4 |
833 | =head1 SEE ALSO |
834 | |
1fef88e7 |
835 | perlref(1), perllol(1), perldata(1), perlobj(1) |
4633a7c4 |
836 | |
837 | =head1 AUTHOR |
838 | |
9607fc9c |
839 | Tom Christiansen <F<tchrist@perl.com>> |
4633a7c4 |
840 | |
6ba6f0ec |
841 | Last update (by Tom): |
28757baa |
842 | Wed Oct 23 04:57:50 MET DST 1996 |
6ba6f0ec |
843 | |
844 | Last update (by Casey West, <F<casey@geeknest.com>> |
845 | Mon Sep 17 13:33:41 EDT 2001 |