Let's tackle this one step at a time. That is, let's deal with plain, flat hashes before we look at complex data structures. Say you want a hash with names of your friends as keys, and their telephone numbers as values.
# Snippet 1 - a stepping stone
use strict;
use warnings;
use Data::Dumper;
# The phone book in an ordinary format,
# as it might be read from a text file for example
my $numbers =
"Alice: 555 1234\n" .
"Bob: 555 9876\n" .
"Charlie: 555 2580";
# The hash. Still empty.
my %phonebook = ();
# Split $numbers on newlines, then iterate over the returned elements
# Then get the name and the number from each element and store them in
+ the hash.
for my $line ( split(/\n/, $numbers) ) {
my ($name,$number) = split(/:\s+/, $line);
$phonebook{$name} = $number;
}
# Bob's a cool guy. I should call him. What's his number again?
print "Bob's digits are $phonebook{Bob}\n\n";
# Heck, Alice, Bob, Charlie -- they're all pretty cool!
print Dumper \%phonebook;
Output:
Bob's digits are 555 9876
$VAR1 = {
'Bob' => '555 9876',
'Alice' => '555 1234',
'Charlie' => '555 2580'
};
There's a number of things to learn from this snippet:
- When you're talking about a hash as a whole (as opposed to a single element in it), you use the % sigil, as in %phonebook = (); and print Dumper \%phonebook;
- If you're storing a key/value pair in a hash, or retrieving the value associated with a given key, you use the $ sigil, as in $phonebook{$name} = $number; and print "Bob's digits are $phonebook{Bob}\n\n";
- To specify the key you want to use, either for storing or fetching a value, you use the curly braces { and } around the key
Moving on. Values in a hash can hold any scalar - strings, numbers, references... Complex data structures in Perl all revolve around references. In your case, these will be references to hashes. There are three ways to create them. Let's add a feature to our phone book that allows us to store different kind of phone numbers (office, home, mobile, ...) for our friends.
# Snippet 2a - another stepping stone
use strict;
use warnings;
use Data::Dumper;
# Create a normal hash.
my %alice = (
home => "555 1234",
work => "555 9876",
mobile => "555 2580",
);
# And another one.
my %bob = (
home => "555 2345",
work => "555 8765",
mobile => "555 1357",
);
my %phonebook = ();
$phonebook{Alice} = \%alice; # Method 1: Store a direct reference t
+o the %alice hash
$phonebook{Bob} = { %bob }; # Method 2: Create an anonymous hash r
+ef, with the contents of %bob
$phonebook{Charlie} = { # Method 3: Create and store an anonym
+ous hash ref directly
home => "555 3456",
work => "555 7654",
mobile => "555 2468"
};
# Alice's a cool lady. I want to call her at her home number!
print "Alice's home number is $phonebook{Alice}->{home}\n";
# She's not there. Maybe she's with Charlie, let's call his cell phone
+.
print "Charlie's mobile number is $phonebook{Charlie}->{mobile}\n\n";
# Gimme all their digits!
print Dumper \%phonebook;
Output:
Alice's home number is 555 1234
Charlie's mobile number is 555 2468
$VAR1 = {
'Bob' => {
'work' => '555 8765',
'home' => '555 2345',
'mobile' => '555 1357'
},
'Alice' => {
'work' => '555 9876',
'mobile' => '555 2580',
'home' => '555 1234'
},
'Charlie' => {
'work' => '555 7654',
'mobile' => '555 2468',
'home' => '555 3456'
}
};
To see the difference between method 1 and method 2, append the following lines to the above snippet:
# Snippet 2b - append to snippet 2a
for (1..3) {
printf "Alice and Bob: %s and %s\n", \%alice, {%bob}
}
Alice and Bob: HASH(0x328358) and HASH(0x380138)
Alice and Bob: HASH(0x328358) and HASH(0x3801e0)
Alice and Bob: HASH(0x328358) and HASH(0x380168)
You'll see that referring to an existing hash (as with \%alice) will constantly give the same reference, but creating a new anonymous hash (as with {%bob}) will give you a new value every time. Why is this relevant? Add the following lines to the code:
# Snippet 2c -- append after 2b
delete $alice{home}; # Delete Alice's home number **from he
+r original hash**
delete $bob{home}; # Delete Bob's home number **from his
+orignal hash** too
delete $phonebook{Charlie}; # Let's not clutter the output
print Dumper \%phonebook;
$VAR1 = {
'Bob' => {
'work' => '555 8765',
'home' => '555 2345',
'mobile' => '555 1357'
},
'Alice' => {
'work' => '555 9876',
'mobile' => '555 2580'
}
};
You'll see that, even though we've deleted a number from Alice's hash, and one from Bob's hash, Bob still has his home number in %phonebook whereas Alice doesn't. Why is that? It's because $phonebook{Alice} is a reference to %alice, but $phonebook{Bob} holds an anonymous hashref. The difference is subtle, but worth pointing out.
Does this mean one method is better than the other? Oh, not at all - it all depends on what you need. But I digress.
This should get you on your way. However, what you want precisely is a little unclear to me. The value associated with <$secondary>, what do you want this to be? Your desired output seems to suggest an array reference, but I can't tell from your code. Assuming that's what you want, though, how about this:
# Snippet 3 - your answer?
use strict;
use warnings;
use Data::Dumper;
my @primary = qw(foo-Alice bar-Bob);
my @secondary = qw(p0-home p1-work p2-mobile);
my @tertiary = qw(itemA-555abcd itemB-555zxyw);
my %phonebook = ();
for my $primary_element (@primary) {
for my $secondary_element (@secondary) {
# Similar to method 1 from snippet 2a:
# a reference directly to @tertiary
$phonebook{$primary_element}->{$secondary_element} = \@ter
+tiary;
# -- or --
# Similar to method 2 from snippet 2a:
# a new anonymous array reference, containing the elements
+ from @tertiary
$phonebook{$primary_element}->{$secondary_element} = [ @te
+rtiary ];
}
}
print Dumper \%phonebook;
Output:
$VAR1 = {
'bar-Bob' => {
'p1-work' => [
'itemA-555abcd',
'itemB-555zxyw'
],
'p0-home' => [
'itemA-555abcd',
'itemB-555zxyw'
],
'p2-mobile' => [
'itemA-555abcd',
'itemB-555zxyw'
]
},
'foo-Alice' => {
'p1-work' => [
'itemA-555abcd',
'itemB-555zxyw'
],
'p0-home' => [
'itemA-555abcd',
'itemB-555zxyw'
],
'p2-mobile' => [
'itemA-555abcd',
'itemB-555zxyw'
]
}
};
Edit: fixed two typos and one slightly misleading comment