Learning Perl Objects, References & ModulesLearning Perl Objects, References & ModulesSearch this book

3.6. Nested Data Structures

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

For example, 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 was passed to the subroutine. Now group them all:

my @all_with_names = (
  \@skipper_with_name,
  \@professor_with_name,
  \@gilligan_with_name,
);

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

Figure 3-1

Figure 3-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 would you access that array reference? Using your rules again, it's ${$all_with_names[2]}[1]. In other words, taking $all_with_names[2], you dereference it in an expression that would be something like $DUMMY[1] as an ordinary array, so you'll place {$all_with_names[2]} in place of DUMMY.

How do you 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. $person will be each of $all_with_names[0], $all_with_names[1], and $all_with_names[2], as the loop progresses. When you dereference $$person[0], you get "Skipper," "Professor," and "Gilligan," respectively. $$person[1] is the corresponding array reference of provisions for that person.

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

for my $person (@all_with_names) {
  check_required_items(@$person);
}

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 takes over your job after you have left.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.