On 2/10/06 Eric Lease Morgan wrote:
>On Feb 10, 2006, at 3:51 PM, Jonathan Gorman wrote:
>>> How do I loop through a reference to an array?
>>>
>>> I have the following data structure:
>>>
>>>  my %facets = (
>>>    'audiences' => [('freshman', 'senior')],
>>>    'subjects'  => [('music', 'history')],
>>>    'tools'     => [('dictionaries', 'catalogs')]
>>>  );
>>>
>>>  foreach my $key (sort(keys(%facets))) { print $key, "\n" }
>>
>> Quick short answer, @{$facets{$key}}..so
>
>
>Thank you for the quick responses. Tastes great; less filling.
>
>Now I'm going to make each value in the referenced array a reference  
>to a hash; I'm going to make my data structure deeper. 'More later.

Eric -- Then why use an array? Do you need to process things in a
certain non-alphbetical order, such as 'dictionaries' before 'catalogs'? 

If you substitute references to hashes for the elements of your above
arrays, you'll lose the names, and only have the order to go on for
knowing what they contain.

This:

my %facets = (
   'audiences' => [('freshman', 'senior')],
   'subjects'  => [('music', 'history')],
   'tools'     => [('dictionaries', 'catalogs')]
);

would become:

my %facets = (
   'audiences' => [(\%freshman, \%senior)],
   'subjects'  => [(\%music, \%history)],
   'tools'     => [(\%dictionaries, \%catalogs)]
);

but then you can't use those hash names for de-referencing the interior
hashes.

Oh, you just posted another question:

>Since that worked so well, I'll ask this question. Given the  
>following data structure, how do I print out something like this:
>
>   tools
>     dictionaries
>       websters - http://websters.com
>       oxford - http://oxford.edu
>     catalogs
>       und - http://catalog.nd.edu
>       worldcat - http://worldcat.com
>
>
c>
>
>This code doesn't cut it:
>
>   foreach my $key (sort(keys(%facets))) {
>
>   print $key, "\n";
>   
>   foreach my $term (@{$facets{$key}}) {
>   
>     print "\t", $term, "\n";
>   
>   }
>   
>   }
>

This would work better (eliminate the arrays):

my %facets = (

    'tools' => {
       'dictionaries' => {
         'websters' => 'http://websters.com',
         'oxford' => 'http://oxford.edu'
        },

       'catalogs' => {
         'und' => 'http://catalog.nd.edu',
         'worldcat' => 'http://worldcat.com'
        },
     },
     
     # other elements of %facets

   );

# access
my $wbstr_url    = $facets{tools}->{dictionaries}->{websters}; 
 # 'http://websters.com'
my $wrldct_url   = $facets{tools}->{catalogs}->{worldcat};
 # 'http://worldcat.com'

# iterate -- watch out for email line-breaking
foreach my $facet_key (keys %facets) {
  foreach my $sub_key (keys %{ $facets{$facet_key} } ) {
    foreach my $inner_key (keys %{ $facets{$facet_key}->{$sub_key} } ) {
      print "$facet_key: $sub_key: $inner_key:
$facets{$facet_key}->{$sub_key}->{$inner_key} \n";
    }
  }
}

# prints:
tools: catalogs: worldcat: http://worldcat.com 
tools: catalogs: und: http://catalog.nd.edu 
tools: dictionaries: oxford: http://oxford.edu 
tools: dictionaries: websters: http://websters.com 

That's not so easy to read, and very redundant as far as de-referencing.

# iterate -- a little easier to keep track
foreach my $facet_key (keys %facets) {
  my %sub_hash    = %{ $facets{$facet_key} };
  for my $sub_key (keys %sub_hash) {
    my %inner_hash    = %{ $sub_hash{$sub_key} };
    foreach my $inner_key (keys %inner_hash) {
      print "$facet_key: $sub_key: $inner_key: $inner_hash{$inner_key}
\n";
    }
  }
}

# prints:
tools: dictionaries: oxford: http://oxford.edu 
tools: dictionaries: websters: http://websters.com 
tools: catalogs: worldcat: http://worldcat.com 
tools: catalogs: und: http://catalog.nd.edu 

Note that I didn't do any sorting in either of the above.

Programming Perl's little chapter section on data structures is
practically worthless unless you already understand nested references,
which is what it's supposed to be explaining. It just makes your head
spin. (My opinion, of course.) After years, it's easy to understand, but
I don't use it to teach from.

The main thing about multi-level data structures is to start from the
innermost elements and work outward. Build outward each level only after
you're sure you have the inner level down. If you use nested foreach()es
against the keys of your nested hashes, use different names for the keys
at each level.

If you use arrays, remember that you gain order, but you may only refer
to the elements by index, i.e., $array[0], array[1], etc.

Finally, I find that in practice I rarely need to iterate through an
entire nested structure and print or process every successive element.
Usually I already know one or more of the inner hash keys. See my
examples above labeled # access.

Taking a lesson from Extreme Programming, write the routine that is
supposed to do what you want, not a routine that just explores your data
structure. Feed your data structure to your routine, and tweak until the
correct result appears.

Data::Dummper can also be a great help in seeing how your data structure
is actually composed (although it sends warnings if any of your
structure's sub-elements is a subroutine reference).

Using the same %facets hash I built above,

use Data::Dumper;
print Dumper(\%facets); # note that's a reference to %facets

#Prints:

$VAR1 = {
          'tools' => {
                  'catalogs' => {
                             'worldcat' => 'http://worldcat.com',
                             'und' => 'http://catalog.nd.edu'
                            },
                  'dictionaries' => {
                             'oxford' => 'http://oxford.edu',
                             'websters' => 'http://websters.com'
                           }
             }
        };


[All code tested]

HTH and Good luck,






- Bruce

__bruce__van_allen__santa_cruz__ca__

Reply via email to