Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

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;


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;


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;


$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

In reply to Re: Hashes... Light switch isn't coming on by muba
in thread Hashes... Light switch isn't coming on by agentorange

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others scrutinizing the Monastery: (3)
    As of 2018-05-24 21:10 GMT
    Find Nodes?
      Voting Booth?