4.6. Nested Data StructuresIn 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 = ( \@skipper_with_name, \@professor_with_name, \@gilligan_with_name, ); 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 arraysTherefore, $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) { 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 will take over your job after you have left.[*]
|