X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pod%2Fperldsc.pod;h=fd6403b7e729e18beac99c70e4c4538869ec6f90;hb=9af228c62a22d61074ac942be277a5f0b4bd7aff;hp=c7c1be29ee5f358ac75b55504c44833258a810e9;hpb=6ba6f0ecc2918dcf7dd01bb4421f3880d6d4c6de;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pod/perldsc.pod b/pod/perldsc.pod index c7c1be2..fd6403b 100644 --- a/pod/perldsc.pod +++ b/pod/perldsc.pod @@ -1,4 +1,5 @@ =head1 NAME +X X X perldsc - Perl Data Structures Cookbook @@ -15,14 +16,14 @@ hacked Perl's internal symbol table directly, a strategy that proved hard to develop and maintain--to put it mildly. The 5.0 release of Perl let us have complex data structures. You -may now write something like this and all of a sudden, you'd have a array +may now write something like this and all of a sudden, you'd have an array with three dimensions! - my @AoA; - for my $x (1 .. 10) { - for my $y (1 .. 10) { - for my $z (1 .. 10) { - $AoA[$x][$y][$z] = $x ** $y + $z; + for $x (1 .. 10) { + for $y (1 .. 10) { + for $z (1 .. 10) { + $AoA[$x][$y][$z] = + $x ** $y + $z; } } } @@ -32,7 +33,7 @@ elaborate construct than meets the eye! How do you print it out? Why can't you say just C? How do you sort it? How can you pass it to a function or get one of these back -from a function? Is is an object? Can you save it to disk to read +from a function? Is it an object? Can you save it to disk to read back later? How do you access whole rows or columns of that matrix? Do all the values have to be numeric? @@ -68,6 +69,7 @@ But for now, let's look at general issues common to all these types of data structures. =head1 REFERENCES +X X X X The most important thing to understand about all data structures in Perl -- including multidimensional arrays--is that even though they might @@ -75,8 +77,9 @@ appear otherwise, Perl C<@ARRAY>s and C<%HASH>es are all internally one-dimensional. They can hold only scalar values (meaning a string, number, or a reference). They cannot directly contain other arrays or hashes, but instead contain I to other arrays or hashes. +X X -You can't use a reference to a array or hash in quite the same way that you +You can't use a reference to an array or hash in quite the same way that you would a real array or hash. For C or C++ programmers unused to distinguishing between arrays and pointers to the same, this can be confusing. If so, just think of it as the difference between a structure @@ -102,11 +105,7 @@ Now, because the top level contains only references, if you try to print out your array in with a simple print() function, you'll get something that doesn't look very nice, like this: - my @AoA = ( - [2, 3, ], - [4, 5, 7], - [0, ], - ); + @AoA = ( [2, 3], [4, 5, 7], [0] ); print $AoA[1][2]; 7 print @AoA; @@ -127,46 +126,80 @@ elements or else taking a reference to the same memory location repeatedly. Here's the case where you just get the count instead of a nested array: - my @AoA; - for my $i (1..10) { - my @array = somefunc($i); - $AoA[$i] = @array; # WRONG! + for $i (1..10) { + @array = somefunc($i); + $AoA[$i] = @array; # WRONG! } That's just the simple case of assigning an array to a scalar and getting its element count. If that's what you really and truly want, then you might do well to consider being a tad more explicit about it, like this: - my @counts; - for my $i (1..10) { - my @array = somefunc($i); - $counts[$i] = scalar @array; + for $i (1..10) { + @array = somefunc($i); + $counts[$i] = scalar @array; } -Here's the right way to do the reference C<@array>: +Here's the case of taking a reference to the same memory location +again and again: - my @AoA - for my $i (1..10) { - my @array = somefunc($i); - $AoA[$i] = [ @array ]; + for $i (1..10) { + @array = somefunc($i); + $AoA[$i] = \@array; # WRONG! + } + +So, what's the big problem with that? It looks right, doesn't it? +After all, I just told you that you need an array of references, so by +golly, you've made me one! + +Unfortunately, while this is true, it's still broken. All the references +in @AoA refer to the I, and they will therefore all hold +whatever was last in @array! It's similar to the problem demonstrated in +the following C program: + + #include + main() { + struct passwd *getpwnam(), *rp, *dp; + rp = getpwnam("root"); + dp = getpwnam("daemon"); + + printf("daemon name is %s\nroot name is %s\n", + dp->pw_name, rp->pw_name); + } + +Which will print + + daemon name is daemon + root name is daemon + +The problem is that both C and C are pointers to the same location +in memory! In C, you'd have to remember to malloc() yourself some new +memory. In Perl, you'll want to use the array constructor C<[]> or the +hash constructor C<{}> instead. Here's the right way to do the preceding +broken code fragments: +X<[]> X<{}> + + for $i (1..10) { + @array = somefunc($i); + $AoA[$i] = [ @array ]; } The square brackets make a reference to a new array with a I -of what's in C<@array>. +of what's in @array at the time of the assignment. This is what +you want. Note that this will produce something similar, but it's much harder to read: - my @AoA; - for my $i (1..10) { - my @array = somefunc($i); - @{ $AoA[$i] } = @array; + for $i (1..10) { + @array = 0 .. $i; + @{$AoA[$i]} = @array; } Is it the same? Well, maybe so--and maybe not. The subtle difference is that when you assign something in square brackets, you know for sure it's always a brand new reference with a new I of the data. -Something else could be going on in this new case with the C<@{ $AoA[$i]} }> +Something else could be going on in this new case with the C<@{$AoA[$i]}> dereference on the left-hand-side of the assignment. It all depends on whether C<$AoA[$i]> had been undefined to start with, or whether it already contained a reference. If you had already populated @AoA with @@ -177,7 +210,7 @@ references, as in Then the assignment with the indirection on the left-hand-side would use the existing reference that was already there: - @{ $AoA[3] } = @array; + @{$AoA[3]} = @array; Of course, this I have the "interesting" effect of clobbering @another_array. (Have you ever noticed how when a programmer says @@ -192,10 +225,9 @@ efficient. Surprisingly, the following dangerous-looking construct will actually work out fine: - my @AoA; - for my $i (1..10) { - my @array = somefunc($i); - $AoA[$i] = \@array; + for $i (1..10) { + my @array = somefunc($i); + $AoA[$i] = \@array; } That's because my() is more of a run-time statement than it is a @@ -214,15 +246,17 @@ do the right thing behind the scenes. In summary: - $AoA[$i] = [ @array ]; # usually best - $AoA[$i] = \@array; # perilous; just how my() is that array? - @{ $AoA[$i] } = @array; # way too tricky for most programmers + $AoA[$i] = [ @array ]; # usually best + $AoA[$i] = \@array; # perilous; just how my() was that array? + @{ $AoA[$i] } = @array; # way too tricky for most programmers =head1 CAVEAT ON PRECEDENCE +X X -Speaking of things like C<@{ $AoA[$i] }>, the following are actually the +Speaking of things like C<@{$AoA[$i]}>, the following are actually the same thing: +X<< -> >> $aref->[2][2] # clear $$aref[2][2] # confusing @@ -256,9 +290,9 @@ also disallow accidental "symbolic dereferencing". Therefore if you'd done this: my $aref = [ - [ 'fred', 'barney', 'pebbles', 'bambam', 'dino', ], - [ 'homer', 'bart', 'marge', 'maggie', ], - [ 'george', 'jane', 'elroy', 'judy', ], + [ "fred", "barney", "pebbles", "bambam", "dino", ], + [ "homer", "bart", "marge", "maggie", ], + [ "george", "jane", "elroy", "judy", ], ]; print $aref[2][2]; @@ -270,6 +304,10 @@ variable, and it would thereby remind you to write instead: print $aref->[2][2] =head1 DEBUGGING +X X +X X X X +X X +X X Before version 5.002, the standard Perl debugger didn't do a very nice job of printing out complex data structures. With 5.002 or above, the @@ -303,184 +341,172 @@ here are short code examples illustrating access of various types of data structures. =head1 ARRAYS OF ARRAYS +X X -=head2 Declaration of a ARRAY OF ARRAYS +=head2 Declaration of an ARRAY OF ARRAYS - my @AoA = ( - [ 'fred', 'barney' ], - [ 'george', 'jane', 'elroy' ], - [ 'homer', 'marge', 'bart' ], + @AoA = ( + [ "fred", "barney" ], + [ "george", "jane", "elroy" ], + [ "homer", "marge", "bart" ], ); -=head2 Generation of a ARRAY OF ARRAYS +=head2 Generation of an ARRAY OF ARRAYS # reading from file - my @AoA; while ( <> ) { push @AoA, [ split ]; } # calling a function - my @AoA; - foreach my $i ( 1 .. 10 ) { + for $i ( 1 .. 10 ) { $AoA[$i] = [ somefunc($i) ]; } # using temp vars - my @AoA; - foreach my $i ( 1 .. 10 ) { - my @tmp = somefunc($i); - $AoA[$i] = [ @tmp ]; + for $i ( 1 .. 10 ) { + @tmp = somefunc($i); + $AoA[$i] = [ @tmp ]; } # add to an existing row - push @{ $AoA[0] }, 'wilma', 'betty'; - -=head2 Access and Printing of a ARRAY OF ARRAYS + push @{ $AoA[0] }, "wilma", "betty"; - my @AoA; +=head2 Access and Printing of an ARRAY OF ARRAYS # one element - $AoA[0][0] = 'Fred'; + $AoA[0][0] = "Fred"; # another element $AoA[1][1] =~ s/(\w)/\u$1/; # print the whole thing with refs - foreach my $aref ( @AoA ) { + for $aref ( @AoA ) { print "\t [ @$aref ],\n"; } # print the whole thing with indices - foreach my $i ( 0 .. $#AoA ) { - print "\t [ @{ $AoA[$i] } ],\n"; + for $i ( 0 .. $#AoA ) { + print "\t [ @{$AoA[$i]} ],\n"; } # print the whole thing one at a time - foreach my $i ( 0 .. $#AoA ) { - foreach my $j ( 0 .. $#{ $AoA[$i] } ) { - print "element $i $j is $AoA[$i][$j]\n"; + for $i ( 0 .. $#AoA ) { + for $j ( 0 .. $#{ $AoA[$i] } ) { + print "elt $i $j is $AoA[$i][$j]\n"; } } =head1 HASHES OF ARRAYS +X X =head2 Declaration of a HASH OF ARRAYS - my %HoA = ( - flintstones => [ 'fred', 'barney' ], - jetsons => [ 'george', 'jane', 'elroy' ], - simpsons => [ 'homer', 'marge', 'bart' ], + %HoA = ( + flintstones => [ "fred", "barney" ], + jetsons => [ "george", "jane", "elroy" ], + simpsons => [ "homer", "marge", "bart" ], ); =head2 Generation of a HASH OF ARRAYS # reading from file # flintstones: fred barney wilma dino - my %HoA; while ( <> ) { - next unless s/^([^:]*):\s*//; + next unless s/^(.*?):\s*//; $HoA{$1} = [ split ]; } # reading from file; more temps # flintstones: fred barney wilma dino - my %HoA; - while ( my $line = <> ) { - my ($who, $rest) = split /:\s*/, $line, 2; - my @fields = split ' ', $rest; - $HoA{$who} = [ @fields ]; + while ( $line = <> ) { + ($who, $rest) = split /:\s*/, $line, 2; + @fields = split ' ', $rest; + $HoA{$who} = [ @fields ]; } # calling a function that returns a list - my %HoA; - foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { + for $group ( "simpsons", "jetsons", "flintstones" ) { $HoA{$group} = [ get_family($group) ]; } # likewise, but using temps - my %HoA; - foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { - my @members = get_family($group); - $HoA{$group} = [ @members ]; + for $group ( "simpsons", "jetsons", "flintstones" ) { + @members = get_family($group); + $HoA{$group} = [ @members ]; } # append new members to an existing family - push @{ $HoA{flintstones} }, 'wilma', 'betty'; + push @{ $HoA{"flintstones"} }, "wilma", "betty"; =head2 Access and Printing of a HASH OF ARRAYS - my %HoA; - # one element - $HoA{flintstones}[0] = 'Fred'; + $HoA{flintstones}[0] = "Fred"; # another element $HoA{simpsons}[1] =~ s/(\w)/\u$1/; # print the whole thing - foreach my $family ( keys %HoA ) { - print "$family: @{ $HoA{$family} }\n"; + foreach $family ( keys %HoA ) { + print "$family: @{ $HoA{$family} }\n" } # print the whole thing with indices - foreach my $family ( keys %HoA ) { - print 'family: '; - foreach my $i ( 0 .. $#{ $HoA{$family} } ) { + foreach $family ( keys %HoA ) { + print "family: "; + foreach $i ( 0 .. $#{ $HoA{$family} } ) { print " $i = $HoA{$family}[$i]"; } print "\n"; } # print the whole thing sorted by number of members - sub num_members { - @{ $HoA{$b} } <=> @{ $HoA{$a} } - } - foreach my $family ( sort num_members keys %HoA ) { + foreach $family ( sort { @{$HoA{$b}} <=> @{$HoA{$a}} } keys %HoA ) { print "$family: @{ $HoA{$family} }\n" } # print the whole thing sorted by number of members and name - sub members_and_name { - @{ $HoA{$b} } <=> @{ $HoA{$a} } - || - $a cmp $b - } - foreach my $family ( sort members_and_name keys %HoA ) { + foreach $family ( sort { + @{$HoA{$b}} <=> @{$HoA{$a}} + || + $a cmp $b + } keys %HoA ) + { print "$family: ", join(", ", sort @{ $HoA{$family} }), "\n"; } =head1 ARRAYS OF HASHES +X X -=head2 Declaration of a ARRAY OF HASHES +=head2 Declaration of an ARRAY OF HASHES - my @AoH = ( + @AoH = ( { - Lead => 'fred', - Friend => 'barney', + Lead => "fred", + Friend => "barney", }, { - Lead => 'george', - Wife => 'jane', - Son => 'elroy', + Lead => "george", + Wife => "jane", + Son => "elroy", }, { - Lead => 'homer', - Wife => 'marge', - Son => 'bart', + Lead => "homer", + Wife => "marge", + Son => "bart", } ); -=head2 Generation of a ARRAY OF HASHES +=head2 Generation of an ARRAY OF HASHES # reading from file # format: LEAD=fred FRIEND=barney - my @AoH; while ( <> ) { - my $rec = {}; - foreach my $field ( split ) { - my($key, $value) = split /=/, $field; - $rec->{$key} = $value; + $rec = {}; + for $field ( split ) { + ($key, $value) = split /=/, $field; + $rec->{$key} = $value; } push @AoH, $rec; } @@ -489,81 +515,77 @@ types of data structures. # reading from file # format: LEAD=fred FRIEND=barney # no temp - my @AoH; while ( <> ) { push @AoH, { split /[\s+=]/ }; } # calling a function that returns a key/value pair list, like - # lead => 'fred', daughter => 'pebbles' - my @AoH; - while ( my %fields = getnextpairset() ) { + # "lead","fred","daughter","pebbles" + while ( %fields = getnextpairset() ) { push @AoH, { %fields }; } # likewise, but using no temp vars - my @AoH; while (<>) { push @AoH, { parsepairs($_) }; } # add key/value to an element - $AoH[0]{pet} = 'dino'; + $AoH[0]{pet} = "dino"; $AoH[2]{pet} = "santa's little helper"; -=head2 Access and Printing of a ARRAY OF HASHES - - my @AoH; +=head2 Access and Printing of an ARRAY OF HASHES # one element - $AoH[0]{lead} = 'fred'; + $AoH[0]{lead} = "fred"; # another element $AoH[1]{lead} =~ s/(\w)/\u$1/; # print the whole thing with refs - foreach my $href ( @AoH ) { - print '{ '; - foreach my $role ( keys %$href ) { - print "$role = $href->{$role} "; + for $href ( @AoH ) { + print "{ "; + for $role ( keys %$href ) { + print "$role=$href->{$role} "; } print "}\n"; } # print the whole thing with indices - foreach my $i ( 0 .. $#AoH ) { + for $i ( 0 .. $#AoH ) { print "$i is { "; - foreach my $role ( keys %{ $AoH[$i] } ) { - print "$role = $AoH[$i]{$role} "; + for $role ( keys %{ $AoH[$i] } ) { + print "$role=$AoH[$i]{$role} "; } print "}\n"; } # print the whole thing one at a time - foreach my $i ( 0 .. $#AoH ) { - foreach my $role ( keys %{ $AoH[$i] } ) { - print "element $i $role is $AoH[$i]{$role}\n"; + for $i ( 0 .. $#AoH ) { + for $role ( keys %{ $AoH[$i] } ) { + print "elt $i $role is $AoH[$i]{$role}\n"; } } =head1 HASHES OF HASHES +X X =head2 Declaration of a HASH OF HASHES - my %HoH = ( + %HoH = ( flintstones => { - lead => 'fred', - pal => 'barney', + lead => "fred", + pal => "barney", }, jetsons => { - lead => 'george', - wife => 'jane', - 'his boy' => 'elroy', + lead => "george", + wife => "jane", + "his boy" => "elroy", }, simpsons => { - lead => 'homer', - wife => 'marge', - kid => 'bart', + lead => "homer", + wife => "marge", + kid => "bart", }, ); @@ -571,126 +593,108 @@ types of data structures. # reading from file # flintstones: lead=fred pal=barney wife=wilma pet=dino - my %HoH; while ( <> ) { - next unless s/^([^:]*):\s*//; - my $who = $1; - for my $field ( split ) { - my($key, $value) = split /=/, $field; + next unless s/^(.*?):\s*//; + $who = $1; + for $field ( split ) { + ($key, $value) = split /=/, $field; $HoH{$who}{$key} = $value; } # reading from file; more temps - my %HoH; while ( <> ) { - next unless s/^([^:]*):\s*//; - my $who = $1; - my $rec = {}; + next unless s/^(.*?):\s*//; + $who = $1; + $rec = {}; $HoH{$who} = $rec; - foreach my $field ( split ) { - my($key, $value) = split /=/, $field; - $rec->{$key} = $value; + for $field ( split ) { + ($key, $value) = split /=/, $field; + $rec->{$key} = $value; } } # calling a function that returns a key,value hash - my %HoH; - foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { + for $group ( "simpsons", "jetsons", "flintstones" ) { $HoH{$group} = { get_family($group) }; } # likewise, but using temps - my %HoH; - foreach my $group ( 'simpsons', 'jetsons', 'flintstones' ) { - my %members = get_family($group); + for $group ( "simpsons", "jetsons", "flintstones" ) { + %members = get_family($group); $HoH{$group} = { %members }; } # append new members to an existing family - my %HoH; - my %new_folks = ( - wife => 'wilma', - pet => 'dino', + %new_folks = ( + wife => "wilma", + pet => "dino", ); - foreach my $what (keys %new_folks) { + for $what (keys %new_folks) { $HoH{flintstones}{$what} = $new_folks{$what}; } =head2 Access and Printing of a HASH OF HASHES - %HoH; - # one element - $HoH{flintstones}{wife} = 'wilma'; + $HoH{flintstones}{wife} = "wilma"; # another element $HoH{simpsons}{lead} =~ s/(\w)/\u$1/; # print the whole thing - foreach my $family ( keys %HoH ) { + foreach $family ( keys %HoH ) { print "$family: { "; - foreach my $role ( keys %{ $HoH{$family} } ) { - print "$role = $HoH{$family}{$role} "; + for $role ( keys %{ $HoH{$family} } ) { + print "$role=$HoH{$family}{$role} "; } print "}\n"; } # print the whole thing somewhat sorted - foreach my $family ( sort keys %HoH ) { + foreach $family ( sort keys %HoH ) { print "$family: { "; - foreach my $role ( sort keys %{ $HoH{$family} } ) { - print "$role = $HoH{$family}{$role} "; + for $role ( sort keys %{ $HoH{$family} } ) { + print "$role=$HoH{$family}{$role} "; } print "}\n"; } + # print the whole thing sorted by number of members - sub num_members { - keys %{ $HoH{$b} } <=> keys %{ $HoH{$a} } - } - foreach my $family ( sort num_members keys %HoH ) { + foreach $family ( sort { keys %{$HoH{$b}} <=> keys %{$HoH{$a}} } keys %HoH ) { print "$family: { "; - foreach my $role ( sort keys %{ $HoH{$family} } ) { - print "$role = $HoH{$family}{$role} "; + for $role ( sort keys %{ $HoH{$family} } ) { + print "$role=$HoH{$family}{$role} "; } print "}\n"; } # establish a sort order (rank) for each role - my %rank; - my $i = 0; - foreach ( qw(lead wife son daughter pal pet) ) { - $rank{$_} = ++$i; - } + $i = 0; + for ( qw(lead wife son daughter pal pet) ) { $rank{$_} = ++$i } # now print the whole thing sorted by number of members - sub num_members { - keys %{ $HoH{$b} } <=> keys %{ $HoH{$a} } - } - sub rank { - $rank{$a} <=> $rank{$b} - } - - foreach my $family ( sort num_members keys %HoH ) { + foreach $family ( sort { keys %{ $HoH{$b} } <=> keys %{ $HoH{$a} } } keys %HoH ) { print "$family: { "; # and print these according to rank order - foreach my $role ( sort rank keys %{ $HoH{$family} } ) { - print "$role = $HoH{$family}{$role} "; + for $role ( sort { $rank{$a} <=> $rank{$b} } keys %{ $HoH{$family} } ) { + print "$role=$HoH{$family}{$role} "; } print "}\n"; } =head1 MORE ELABORATE RECORDS +X X X =head2 Declaration of MORE ELABORATE RECORDS Here's a sample showing how to create and use a record whose fields are of many different sorts: - my $rec = { + $rec = { TEXT => $string, SEQUENCE => [ @old_values ], LOOKUP => { %some_table }, @@ -701,14 +705,14 @@ many different sorts: print $rec->{TEXT}; - print $rec->{SEQUENCE}->[0]; - my $last = pop @{ $rec->{SEQUENCE} }; + print $rec->{SEQUENCE}[0]; + $last = pop @ { $rec->{SEQUENCE} }; - print $rec->{LOOKUP}->{key}; - my($first_k, $first_v) = each %{ $rec->{LOOKUP} }; + print $rec->{LOOKUP}{"key"}; + ($first_k, $first_v) = each %{ $rec->{LOOKUP} }; - my $answer = $rec->{THATCODE}->($arg); - my $result = $rec->{THISCODE}->($arg1, $arg2); + $answer = $rec->{THATCODE}->($arg); + $answer = $rec->{THISCODE}->($arg1, $arg2); # careful of extra block braces on fh ref print { $rec->{HANDLE} } "a string\n"; @@ -719,52 +723,55 @@ many different sorts: =head2 Declaration of a HASH OF COMPLEX RECORDS - my %TV = ( + %TV = ( flintstones => { - series => 'flintstones', + series => "flintstones", nights => [ qw(monday thursday friday) ], members => [ - { name => 'fred', role => 'lead', age => 36, }, - { name => 'wilma', role => 'wife', age => 31, }, - { name => 'pebbles', role => 'kid', age => 4, }, + { name => "fred", role => "lead", age => 36, }, + { name => "wilma", role => "wife", age => 31, }, + { name => "pebbles", role => "kid", age => 4, }, ], }, jetsons => { - series => 'jetsons', + series => "jetsons", nights => [ qw(wednesday saturday) ], members => [ - { name => 'george", role => 'lead', age => 41, }, - { name => 'jane", role => 'wife', age => 39, }, - { name => 'elroy", role => 'kid', age => 9, }, + { name => "george", role => "lead", age => 41, }, + { name => "jane", role => "wife", age => 39, }, + { name => "elroy", role => "kid", age => 9, }, ], }, simpsons => { - series => 'simpsons', + series => "simpsons", nights => [ qw(monday) ], members => [ - { name => 'homer', role => 'lead', age => 34, }, - { name => 'marge', role => 'wife', age => 37, }, - { name => 'bart', role => 'kid', age => 11, }, + { name => "homer", role => "lead", age => 34, }, + { name => "marge", role => "wife", age => 37, }, + { name => "bart", role => "kid", age => 11, }, ], }, ); =head2 Generation of a HASH OF COMPLEX RECORDS -Here's a piece by piece build up of a hash of complex records. We'll -read in a file that has our data in it. + # reading from file + # this is most easily done by having the file itself be + # in the raw data format as shown above. perl is happy + # to parse complex data structures if declared as data, so + # sometimes it's easiest to do that - my %TV = (); - my $rec = {}; - $rec->{series} = 'flintstones'; + # here's a piece by piece build up + $rec = {}; + $rec->{series} = "flintstones"; $rec->{nights} = [ find_days() ]; - my @members = (); + @members = (); # assume this file in field=value syntax - while ( <> ) { - my %fields = split /[\s=]+/, $_; + while (<>) { + %fields = split /[\s=]+/; push @members, { %fields }; } $rec->{members} = [ @members ]; @@ -772,18 +779,19 @@ read in a file that has our data in it. # now remember the whole thing $TV{ $rec->{series} } = $rec; -Now, you might want to make interesting extra fields that -include pointers back into the same data structure so if -change one piece, it changes everywhere, like for example -if you wanted a 'kids' field that was a reference -to an array of the kids' records without having duplicate -records and thus update problems. - - foreach my $family ( keys %TV ) { - my $rec = $TV{$family}; # $rec points to $TV{$family} - my @kids = (); - foreach my $person ( @{ $rec->{members} } ) { - if ( $person->{role} =~ /kid|son|daughter/ ) { + ########################################################### + # now, you might want to make interesting extra fields that + # include pointers back into the same data structure so if + # change one piece, it changes everywhere, like for example + # if you wanted a {kids} field that was a reference + # to an array of the kids' records without having duplicate + # records and thus update problems. + ########################################################### + foreach $family (keys %TV) { + $rec = $TV{$family}; # temp pointer + @kids = (); + for $person ( @{ $rec->{members} } ) { + if ($person->{role} =~ /kid|son|daughter/) { push @kids, $person; } } @@ -791,33 +799,30 @@ records and thus update problems. $rec->{kids} = [ @kids ]; } -You copied the array, but the array itself contains pointers -to uncopied objects. This means that if you make bart get -older via + # you copied the array, but the array itself contains pointers + # to uncopied objects. this means that if you make bart get + # older via $TV{simpsons}{kids}[0]{age}++; -Then this would also change in C<$TV{simpsons}{members}[2]{age}> -because C<$TV{simpsons}{kids}[0]> and C<$TV{simpsons}{members}[2]> -both point to the same underlying anonymous hash table. + # then this would also change in + print $TV{simpsons}{members}[2]{age}; - # print the whole thing - foreach my $family ( keys %TV ) { - print "the $family is on during @{ $TV{$family}{nights} }\n", - "its members are:\n"; + # because $TV{simpsons}{kids}[0] and $TV{simpsons}{members}[2] + # both point to the same underlying anonymous hash table - foraech my $who ( @{ $TV{$family}{members} } ) { + # print the whole thing + foreach $family ( keys %TV ) { + print "the $family"; + print " is on during @{ $TV{$family}{nights} }\n"; + print "its members are:\n"; + for $who ( @{ $TV{$family}{members} } ) { print " $who->{name} ($who->{role}), age $who->{age}\n"; } - - print "it turns out that $TV{$family}{lead} has ", - scalar ( @{ $TV{$family}{kids} } ), - ' kids named ', - join( - ', ', - map { $_->{name} } @{ $TV{$family}{kids} } - ), - "\n"; + print "it turns out that $TV{$family}{lead} has "; + print scalar ( @{ $TV{$family}{kids} } ), " kids named "; + print join (", ", map { $_->{name} } @{ $TV{$family}{kids} } ); + print "\n"; } =head1 Database Ties @@ -838,8 +843,5 @@ perlref(1), perllol(1), perldata(1), perlobj(1) Tom Christiansen > -Last update (by Tom): +Last update: Wed Oct 23 04:57:50 MET DST 1996 - -Last update (by Casey West, > -Mon Sep 17 13:33:41 EDT 2001