Initially, you might gather the data using a simple loop:
my %provisions;
my $person;
while (<>) {
if (/^(\S.*)/) { # a person's name (no leading whitespace)
$person = $1;
$provisions{$person} = [ ] unless exists $provisions{$person};
} elsif (/^\s+(\S.*)/) { # a provision
die "No person yet!" unless defined $person;
push @{ $provisions{$person} }, $1;
} else {
die "I don't understand: $_";
}
}
First, you declare the variables for the resulting hash of provisions
and the current person. For each line that is read, determine if
it's a person or a provision. If
it's a person, remember the name and create the hash
element for that person. The unless exists test
ensures that you won't delete
someone's provision list if his list is split in two
places in the data file. For example, suppose that
"The Skipper" and
" sextant" (note the leading
whitespace) are at the end of the data file in order to list an
additional data item.
The key is the person's name, and the value is
initially a reference to an empty anonymous array. If the line is a
provision, push it to the end of the correct array, using the array
reference.
my %provisions;
my $person;
while (<>) {
if (/^(\S.*)/) { # a person's name (no leading whitespace)
$person = $1;
## $provisions{$person} = [ ] unless exists $provisions{$person};
} elsif (/^\s+(\S.*)/) { # a provision
die "No person yet!" unless defined $person;
push @{ $provisions{$person} }, $1;
} else {
die "I don't understand: $_";
}
}
What happens when you try to store that blue shirt for the Skipper?
While looking at the second line of input, you'll
end up with this effect:
push @{ $provisions{"The Skipper"} }, "blue_shirt";
At this point, $provisions{"The Skipper"}
doesn't exist, but you're trying to
use it as an array reference. To resolve the situation, Perl
automatically inserts a reference to a new empty anonymous array into
the variable and continues the operation. In this case, the reference
to the newly created empty array is dereferenced, and you push the
blue shirt to the provisions list.
This process is called autovivification. Any
nonexisting variable, or a variable containing
undef, which is dereferenced while looking for a
variable location (technically called an lvalue
context), is automatically stuffed with the appropriate
reference to an empty item, and the operation is allowed to proceed.
For example, this works:
my $not_yet; # new undefined variable
@$not_yet = (1, 2, 3);
Here, you dereference the value $not_yet as if it
were an array reference. But since it's initially
undef, Perl acts as if you had said:
my $not_yet;
$not_yet = [ ]; # inserted through autovivification
@$not_yet = (1, 2, 3);
In other words, an initially empty array becomes an array of three
elements.
This autovivification also works for multiple levels of assignment:
my $top;
$top->[2]->[4] = "lee-lou";