Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re: Hashes... Light switch isn't coming on

by muba (Priest)
on Dec 12, 2012 at 18:11 UTC ( #1008548=note: print w/ replies, xml ) Need Help??


in reply to Hashes... Light switch isn't coming on

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:

  1. 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;
  2. 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";
  3. 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


Comment on Re: Hashes... Light switch isn't coming on
Select or Download Code

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1008548]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (11)
As of 2015-07-01 16:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (9 votes), past polls