Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > trying to understand hash of hashes or multidimensional arrays

Reply
Thread Tools

trying to understand hash of hashes or multidimensional arrays

 
 
Sherm Pendley
Guest
Posts: n/a
 
      06-22-2005
writes:

> This problem may be something simple that I am failing to grasp ...
> I've read dozens of postings about 'hashes of hashes' and
> 'multidimensional hashes' and 'hashes of arrays', and I still can't
> figure out how to use such a structure to do what I want.


Reading "perldoc perllol", and "perldoc perldsc" would be a great start.

sherm--
 
Reply With Quote
 
 
 
 
jguad98@hotmail.com
Guest
Posts: n/a
 
      06-22-2005
This problem may be something simple that I am failing to grasp ...
I've read dozens of postings about 'hashes of hashes' and
'multidimensional hashes' and 'hashes of arrays', and I still can't
figure out how to use such a structure to do what I want.

I have a list that I read into an array. Each element is a text string
like this (it's an object identifier):

"region.level.location.system"

There's an unknown number of regions, then for each region there are an
unknown number of levels, in each level an unknown number of locations,
and in each location an unknown number of systems.

The labels or names for each node of the object name may be duplicated
within different 'branches' ... they are unique only within their
context of 'region.level.location.system'. For example, there can be
multiple instances of a 'location' called 'home' as long as each 'home'
is in a different 'region' or 'level'.

So I want to read this text data into my script, store it in a
multidimensional array (or should it be a 'hash of hashes'?). Then I
need to generate a report that shows me the relationships in an orderly
(almost graphic) manner ... I want to be able to print out something
like this (actual formatting is not important, just the organization):

region1

region1.level1
region1.level2

region1.level1.location1
region1.level1.location2

region1.level2.location1
region1.level2.location2

region1.level1.location1.systemA
region1.level1.location1.systemB

region1.level1.location2.systemA
region1.level1.location2.systemB

region1.level2.location1.systemA
region1.level2.location1.systemB


.... so on and so forth ... iterating through every region, every
level, every location, every system

So how can I put the data into a multidimensional array or hash and
then pull that data back out as needed? I've thought of using multiple
arrays and then having elements of arrays referring to other arrays,
but that gives me a headache and I really believe this should be doable
via a single multidimensional hash ... I just can't figure out how.

.....

More on the issue of multidimensional hashes ... I've seen these 2
different structures, and I know they are functionally different, but I
don't understand why and how each should be used:

(example 1) $hashname{$key{$subkey}}

(example 2) $hashname($key}{$subkey}

Can someone explain how these structures are used?

thanks & regards,

John

 
Reply With Quote
 
 
 
 
jguad98@hotmail.com
Guest
Posts: n/a
 
      06-22-2005
.... forgive the typo above ... "example 2" should be:
$hashname{$key}{$subkey}

John

 
Reply With Quote
 
A. Sinan Unur
Guest
Posts: n/a
 
      06-23-2005
wrote in news:1119483448.237142.244340
@g44g2000cwa.googlegroups.com:

> This problem may be something simple that I am failing to grasp ...
> I've read dozens of postings about 'hashes of hashes' and


Well, you should always start with Perl documentation rather than random
postings.

See

perldoc perlreftut

as well as

perldoc perldsc

> I just can't figure out how.


Make an attempt, and we can help you with any hurdles you encounter.

> (example 1) $hashname{$key{$subkey}}
>
> (example 2) $hashname($key}{$subkey}


Example 2 is a syntax error.

Sinan

--
A. Sinan Unur <>
(reverse each component and remove .invalid for email address)

comp.lang.perl.misc guidelines on the WWW:
http://mail.augustmail.com/~tadmc/cl...uidelines.html
 
Reply With Quote
 
Ilmari Karonen
Guest
Posts: n/a
 
      06-23-2005
<> kirjoitti 22.06.2005:
>
> I have a list that I read into an array. Each element is a text string
> like this (it's an object identifier):
>
> "region.level.location.system"


Okay, you can store this in a 4-dimensional hash like this:

my %hash;
foreach my $string (@array) {
my ($region, $level, $location, $system) = split /\./, $string;
$hash{$region}{$level}{$location}{$system}++;
}

The values in the hash will simply be numbers indicating how many
times each identifier has been seen. You don't need to use them for
anything -- it's just the keys that matter.


> need to generate a report that shows me the relationships in an orderly
> (almost graphic) manner ... I want to be able to print out something
> like this (actual formatting is not important, just the organization):
>
> region1
>
> region1.level1
> region1.level2
>
> region1.level1.location1
> region1.level1.location2

[snip]
>
> ... so on and so forth ... iterating through every region, every
> level, every location, every system


For the output you want, the simplest way would be to write four
separate loops, one for each depth. They will all look fairly
similar:

foreach my $region (sort keys %hash) {
print "$region\n";
}

foreach my $region (sort keys %hash) {
my %region = %{ $hash{$region} };
foreach my $level (sort keys %region) {
print "$region.$level\n";
}
}

foreach my $region (sort keys %hash) {
my %region = %{ $hash{$region} };
foreach my $level (sort keys %region) {
my %level = %{ $region{$level} };
foreach my $location (sort keys %level) {
print "$region.$level.$location\n";
}
}
}

foreach my $region (sort keys %hash) {
my %region = %{ $hash{$region} };
foreach my $level (sort keys %region) {
my %level = %{ $region{$level} };
foreach my $location (sort keys %level) {
my %location = %{ $level{$location} };
foreach my $system (sort keys %location) {
print "$region.$level.$location.$system\n";
}
}
}
}

Of course, if you wanted to do the same for a nested hash of arbitrary
depth, you could use a recursive solution:

sub keys_at_depth {
my ($hashref, $depth) = @_;
return sort keys %$hashref if $depth < 2;
my @keys;
foreach my $key (sort keys %$hashref) {
my $subhash = $hashref->{$key};
next unless ref $subhash eq 'HASH';
push @keys, map "$key.$_", keys_at_depth($subhash, $depth-1);
}
return @keys;
}

my $depth = 1;
while (my @keys = keys_at_depth(\%hash, $depth)) {
print "$_\n" for @keys;
$depth++;
}

There, that's much nicer, isn't it? Of course, there are several
other ways to approach your problem as well. For example, you could
instead use four separate hashes, one for each depth:

my (%regions, %levels, %locations, %systems);
foreach my $string (@array) {
my ($region, $level, $location, $system) = split /\./, $string;
$regions {"$region"}++;
$levels {"$region.$level"}++;
$locations{"$region.$level.$location"}++;
$systems {"$region.$level.$location.$system"}++;
}

print "$_\n" for sort keys %regions;
print "$_\n" for sort keys %levels;
print "$_\n" for sort keys %locations;
print "$_\n" for sort keys %systems;

Or you could use an array of hashes:

my @depths;
foreach my $string (@array) {
my @parts = split /\./, $string;
$depths[$_]{join ".", @parts[0 .. $_]}++ for 0 .. $#parts;
}

foreach my $depth (@depths) {
print "$_\n" for sort keys %$depth;
}

There, I don't think it gets any more compact than that. Of course,
to populate @array, you'd use:

my @array = <>;
chomp @array;

and don't forget to start your script with:

#!/usr/bin/perl
use warnings;
use strict;

--
Ilmari Karonen
To reply by e-mail, please replace ".invalid" with ".net" in address.
 
Reply With Quote
 
jguad98@hotmail.com
Guest
Posts: n/a
 
      06-23-2005
My first posting of 'example 2' has a paren where there should be a
curly, but to match the actual code I found in a script, it should be
like this:

$hashname{$key}{bareword} = 'value';

I know this structure is legal (well, it works). I extrapolated that
'bareword' could be replaced with a variable, hence it should work as

$hashname{$key}{$subkey} = 'value';

What is the functional difference between that and

$hashname{$key{$subkey}} = 'value';

?
.....

I scanned the perldocs perllol and perldsc ... the latter one helped
immensely ... I now have a working script using the HoH structure as
in example 1. Thank you, Sherm & Sinan.

 
Reply With Quote
 
A. Sinan Unur
Guest
Posts: n/a
 
      06-23-2005
wrote in news:1119560161.977333.248710
@f14g2000cwb.googlegroups.com:

> What is the functional difference between that and
>
> $hashname{$key{$subkey}} = 'value';


Does this help?

my %key = (
# blah blah
);
my $x = $key{$subkey};

my %hashname = (
# blah blah
);

$hashname{$x} = 'value';

Now, instead of $x, use $key{$subkey}:

$hashname{$key{$subkey}} = 'value';

which is different than

$hashname{$key}{$subkey} = 'value';

Indeed, the latter is the case where the names $key and $subkey convey
the intended meaning.

You should use Data:umper and check out the structure you end up with
following various operations.

And please quote an appropriate amount of context when you reply.

Sinan
--
A. Sinan Unur <>
(reverse each component and remove .invalid for email address)

comp.lang.perl.misc guidelines on the WWW:
http://mail.augustmail.com/~tadmc/cl...uidelines.html
 
Reply With Quote
 
Eric Bohlman
Guest
Posts: n/a
 
      06-23-2005
wrote in news:1119560161.977333.248710
@f14g2000cwb.googlegroups.com:

> I know this structure is legal (well, it works). I extrapolated that
> 'bareword' could be replaced with a variable, hence it should work as
>
> $hashname{$key}{$subkey} = 'value';
>
> What is the functional difference between that and
>
> $hashname{$key{$subkey}} = 'value';
>
> ?


In the first case, you have a hash (%hashname) and you're "subscripting" it
with two scalar variables, $key and $subkey. In the second case, you have
*two* hashes (%hashname and %key) and only one scalar ($subkey); you are
*not* making any use of a scalar called $key. Instead you're looking up
the value for $subkey in %key, and then using that value as a key to set
the corresponding value in %hashname. Two completely different operations.
 
Reply With Quote
 
Tad McClellan
Guest
Posts: n/a
 
      06-23-2005
Eric Bohlman <> wrote:
> wrote in news:1119560161.977333.248710
> @f14g2000cwb.googlegroups.com:
>
>> I know this structure is legal (well, it works). I extrapolated that
>> 'bareword' could be replaced with a variable, hence it should work as
>>
>> $hashname{$key}{$subkey} = 'value';
>>
>> What is the functional difference between that and
>>
>> $hashname{$key{$subkey}} = 'value';
>>
>> ?

>
> In the first case, you have a hash (%hashname) and you're "subscripting" it
> with two scalar variables, $key and $subkey. In the second case, you have
> *two* hashes (%hashname and %key) and only one scalar ($subkey); you are
> *not* making any use of a scalar called $key. Instead you're looking up
> the value for $subkey in %key, and then using that value as a key to set
> the corresponding value in %hashname. Two completely different operations.



And the first one makes use of references, while there are no
references involved with the second one.


--
Tad McClellan SGML consulting
Perl programming
Fort Worth, Texas
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Multidimensional arrays and arrays of arrays Philipp Java 21 01-20-2009 08:33 AM
Hash of hashes, of hashes, of arrays of hashes Tim O'Donovan Perl Misc 5 10-28-2005 05:59 AM
Hashes of hashes or just one hash ? Perl Learner Perl Misc 11 06-09-2005 06:55 AM
Performance Improvement of complex data structure (hash of hashes of hashes) Scott Gilpin Perl Misc 2 08-26-2004 01:02 AM
Sort a hash based on values in the hash stored as arrays of hashes Tore Aursand Perl Misc 3 09-16-2003 10:14 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57