Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Building HoHoH from arbitrary size arrays ?

Reply
Thread Tools

Building HoHoH from arbitrary size arrays ?

 
 
Allan Houston
Guest
Posts: n/a
 
      07-12-2005
Hi,

I've searched and read about everything I can find on trying to do this,
but my only solution I can think of is real, real ugly..

Basically I'm looking to create a sub routine which will query a
database table for the specified rows, and create a hash where each
column is a key in the hash of hashes.

i.e. From a table like so :

+---------------+---------------+------------+------+
| region | location | function | type |
+---------------+---------------+------------+------+
| Aztec West | Aztec West | PE Routers | 7513 |
| Aztec West | Staverton | PE Routers | 7513 |
| Barnsley | Barnsley | PE Routers | 7513 |
| Barnsley | Bradford | PE Routers | 7513 |
| Barnsley | Sheffield | PE Routers | 7513 |
| Basildon | Basildon | PE Routers | 7513 |
| Basildon | Gillingham | PE Routers | 7513 |
-----------------------------------------------------

I'd produce a hash like :

$hash{'Aztec West'}{'Aztec West'}{'PE Routers}{'7513'}
$hash{'Aztec West'}{'Staverton'}{'PE Routers}{'7513'}
$hash{'Barnsley'}{'Barnsley'}{'PE Routers'}{'7513'} etc etc.

The problem being that I'm trying to create a function which will read
in say the first $count columns and return a hash of hashes with a depth
of $count keys.

The only way I can think to do it so far is something like this :

------------------------------------------------------------------------

while (@t=$query->fetchrow_array())
{

if (@t == 1)
{ $hash{$t[0]}=''; }
elsif (@t == 2)
{ $hash{$t[0]}{$t[1]}='';}
elsif (@t == 3)
{ $hash{$t[0]}{$t[1]}{$t[2]}='';}
elsif (@t == 4)
{ $hash{$t[0]}{$t[1]}{$t[2]}{$t[3]}='';}
elsif (@t == 5)
{ $hash{$t[0]}{$t[1]}{$t[2]}{$t[3]}{$t[4]}='';}
elsif (@t == 6)
{ $hash{$t[0]}{$t[1]}{$t[2]}{$t[3]}{$t[4]}{$t[5]}='';}

}

return(\%hash);

------------------------------------------------------------------------

There has to be a more elegant solution than this surely.. Can anyone
point me in the right direction please ?

Cheers,
Allan.
 
Reply With Quote
 
 
 
 
Paul Lalli
Guest
Posts: n/a
 
      07-12-2005
Allan Houston wrote:
> I've searched and read about everything I can find on trying to do this,
> but my only solution I can think of is real, real ugly..
>
> Basically I'm looking to create a sub routine which will query a
> database table for the specified rows, and create a hash where each
> column is a key in the hash of hashes.

<snip>
> The problem being that I'm trying to create a function which will read
> in say the first $count columns and return a hash of hashes with a depth
> of $count keys.


I strongly suspect an AB problem here. Why exactly do you feel the
need to create such a function? What is your *actual* goal?

> There has to be a more elegant solution than this surely.. Can anyone
> point me in the right direction please ?


I don't understand *why* you'd want to do this, but I believe this
meets your criteria:

#!/usr/bin/perl
use strict;
use warnings;
use Data:umper;

my @stuff = qw/foo bar baz bam boom/;

my %h;
my $ref = \%h;
for my $level (@stuff){
$ref->{$level} = {};
$ref = $ref->{$level};
}

print Dumper(\%h);

__END__


$VAR1 = {
'foo' => {
'bar' => {
'baz' => {
'bam' => {
'boom' => {}
}
}
}
}
};




Paul Lalli

 
Reply With Quote
 
 
 
 
Allan Houston
Guest
Posts: n/a
 
      07-12-2005
Paul Lalli wrote:
> Allan Houston wrote:
>
>>I've searched and read about everything I can find on trying to do this,
>>but my only solution I can think of is real, real ugly..
>>
>>Basically I'm looking to create a sub routine which will query a
>>database table for the specified rows, and create a hash where each
>>column is a key in the hash of hashes.

>
> <snip>
>
>>The problem being that I'm trying to create a function which will read
>>in say the first $count columns and return a hash of hashes with a depth
>>of $count keys.

>
>
> I strongly suspect an AB problem here. Why exactly do you feel the
> need to create such a function? What is your *actual* goal?
>
>
>>There has to be a more elegant solution than this surely.. Can anyone
>>point me in the right direction please ?

>
>
> I don't understand *why* you'd want to do this, but I believe this
> meets your criteria:
>
> #!/usr/bin/perl
> use strict;
> use warnings;
> use Data:umper;
>
> my @stuff = qw/foo bar baz bam boom/;
>
> my %h;
> my $ref = \%h;
> for my $level (@stuff){
> $ref->{$level} = {};
> $ref = $ref->{$level};
> }
>
> print Dumper(\%h);
>
> __END__
>
>
> $VAR1 = {
> 'foo' => {
> 'bar' => {
> 'baz' => {
> 'bam' => {
> 'boom' => {}
> }
> }
> }
> }
> };
>
>
>
>
> Paul Lalli
>


Hi Paul,

First off - thanks for your code, its certainly helped me.

The reason I'm doing it this way is that the DBI fetchrow_hashref will
overwrite values where the key has multiple values which is how my data
is stored (unfortunately..)

The sub I'm writing allows me to specify an array of arbitrary columns
and get them returned in a hash hierarchy, which I find useful for
getting at the data quickly and easily.

Far more importantly however, you've shown me how to do something in
perl which I didn't know before - thank you

I made some minor changes to the code you provided to cope with the
multiple key values :


#!/usr/bin/perl
use strict;
use warnings;
use Data:umper;

my @stuff = ([qw/foo bar baz bam boom/],[qw/foo bar wizz wham whallop/]);

my %h;
my $ref = \%h;

foreach my $stuff_ref (@stuff) {
for my $level (@$stuff_ref) {

if (exists $ref->{$level}) { # If the key exists then just move on

$ref = $ref->{$level};
next;
}

$ref->{$level} = {};
$ref = $ref->{$level};
}

$ref = \%h; # Start at the beginning again

}

print Dumper(\%h);

Which seems to work OK. I probably kludged up your beautiful code -
please accept my humble apologies if this is the case.

# ./hashes.pl
$VAR1 = {
'foo' => {
'bar' => {
'baz' => {
'bam' => {
'boom' => {}
}
},
'wizz' => {
'wham' => {
'whallop' => {}
}
}
}
}
};


Cheers,
Allan.
 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      07-12-2005
Allan Houston wrote:
> Paul Lalli wrote:
> > Allan Houston wrote:
> >
> >>I've searched and read about everything I can find on trying to do this,
> >>but my only solution I can think of is real, real ugly..
> >>
> >>Basically I'm looking to create a sub routine which will query a
> >>database table for the specified rows, and create a hash where each
> >>column is a key in the hash of hashes.

> >

>
>
> The reason I'm doing it this way is that the DBI fetchrow_hashref will
> overwrite values where the key has multiple values which is how my data
> is stored (unfortunately..)


Out of curiousity, have you looked at the fetchall_hashref method?
That one reads the entire table, and allows you to specify multiple key
columns.

> The sub I'm writing allows me to specify an array of arbitrary columns
> and get them returned in a hash hierarchy, which I find useful for
> getting at the data quickly and easily.
>
> Far more importantly however, you've shown me how to do something in
> perl which I didn't know before - thank you
>
> I made some minor changes to the code you provided to cope with the
> multiple key values :
>
>
> #!/usr/bin/perl
> use strict;
> use warnings;
> use Data:umper;
>
> my @stuff = ([qw/foo bar baz bam boom/],[qw/foo bar wizz wham whallop/]);
>
> my %h;
> my $ref = \%h;
>
> foreach my $stuff_ref (@stuff) {
> for my $level (@$stuff_ref) {
>
> if (exists $ref->{$level}) { # If the key exists then just move on
>
> $ref = $ref->{$level};
> next;
> }
>
> $ref->{$level} = {};
> $ref = $ref->{$level};
> }
>
> $ref = \%h; # Start at the beginning again
>
> }
>
> print Dumper(\%h);
>
> Which seems to work OK. I probably kludged up your beautiful code -
> please accept my humble apologies if this is the case.


I would just add a statement modifier to the body of the for loop,
rather than the if block and duplicate statements:
for my $level (@stuff){
$ref->{$level} = {} unless exists $ref->{$level};
$ref = $ref->{$level};
}

Paul Lalli

 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      07-12-2005
Paul Lalli wrote:
> I strongly suspect an AB problem here.


.... did I really say that? Sheesh.

s/AB/XY/;


Paul Lalli

 
Reply With Quote
 
Brian McCauley
Guest
Posts: n/a
 
      07-13-2005
Paul Lalli wrote:

> for my $level (@stuff){
> $ref->{$level} = {} unless exists $ref->{$level};
> $ref = $ref->{$level};
> }


When building such a HoHoH there's no way that $ref->{$level} will
exist but be false. As such you don't need the exists() in there...

$ref->{$level} = {} unless $ref->{$level};

....which, of course, simlifies to...

$ref->{$level} ||= {};

....which in turn makes it easy to combine it with the next statement...

$ref = $ref->{$level} ||= {};

....although I tend to use autovivifivation instead...

$ref = \%{$ref->{$level}};

And given a short single statement I tend to opt for the statement
qualifier version of for.

$ref = \%{$ref->{$_}} for @stuff;

In practice you often don't want the bottom level of such a HoHoH to be
an empty hash so I usually use a refererence to reference instead.

my $ref = \\%h;
$ref = \$$ref->{$_} for @stuff;

 
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
Proposing an arbitrary precision class building on BigDecimal andbeing derived from Numeric ulrichmutze@aol.com Ruby 5 02-05-2009 08:13 PM
Multidimensional arrays and arrays of arrays Philipp Java 21 01-20-2009 08:33 AM
building arbitrary files with distutils? Wilbert Berendsen Python 1 03-10-2008 10:14 PM
calling an arbitrary function w/ arbitrary arguments Honestmath C++ 5 12-13-2004 06:18 AM
HoHoH (hash of HoH's) Aaron DeLoach Perl Misc 10 07-20-2004 07:57 PM



Advertisments