Section 4.6.  Nested Data Structures

Table of Contents

4.6. Nested Data Structures

In this example, the array @_ contains two elements, one of which is also an array. What if we take a reference to an array that also contains a reference to an array? We end up with a complex data structure, which can be quite useful.

For example, we can iterate over the data for the Skipper, Gilligan, and the Professor by first building a larger data structure holding the entire list of provision lists:

my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
my @skipper_with_name = ('Skipper', \@skipper);
my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
my @professor_with_name = ('Professor', \@professor);
my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
my @gilligan_with_name = ('Gilligan', \@gilligan);

At this point, @skipper_with_name has two elements, the second of which is an array reference similar to what we passed to the subroutine. Now we group them all:

my @all_with_names = (

Note that we have just three elements, each of which is a reference to an array that has two elements: the name and its corresponding initial provisions. A picture of that is in Figure 4-1.

Figure 4-1. The array @all_with_names holds a multilevel data structure containing strings and references to arrays

Therefore, $all_with_names[2] will be the array reference for the Gilligan's data. If you dereference it as @{$all_with_names[2]}, you get a two-element array, "Gilligan" and another array reference.

How do we access that array reference? Using our rules again, it's ${$all_with_names[2]}[1]. In other words, taking $all_with_names[2], we dereference it in an expression that would be something like $DUMMY[1] as an ordinary array, so we'll place {$all_with_names[2]} in place of DUMMY.

How do we call the existing check_required_items( ) with this data structure? The following code is easy enough.

for my $person (@all_with_names) {
  my $who = $$person[0];
  my $provisions_reference = $$person[1];
  check_required_items($who, $provisions_reference);

This requires no changes to the subroutine. The control variable $person will be each of $all_with_names[0], $all_with_names[1], and $all_with_names[2], as the loop progresses. When we dereference $$person[0], we get "Skipper," "Professor," and "Gilligan," respectively. $$person[1] is the corresponding array reference of provisions for that person.

Of course, we can shorten this as well, since the entire dereferenced array matches the argument list precisely:

for my $person (@all_with_names) {

or even:

check_required_items(@$_) for @all_with_names;

As you can see, various levels of optimization can lead to obfuscation. Be sure to consider where your head will be a month from now when you have to reread your own code. If that's not enough, consider the new person who will take over your job after you have left.[*]

[*] O'Reilly Media has a great book to help you be nice to the next guy. Perl Best Practices by Damian Conway has 256 tips on writing more readable and maintainable Perl code.

Table of Contents
© 2000- NIV