Autovivification within deep nested hash

N

niall.macpherson

I have a very deep nested hash and I need to set a lot of values at one
of the lowest levels.
Eg if I wanted to do something like

$a{b}{c}{d}{e}{f}{'bit1} = 'val1';
$a{b}{c}{d}{e}{f}{'bit2} = 'val2';
......... etc etc
I'd like to be able to assign a variable (say $thisone) to the top
levels ($a{b}{c}{d}{e}{f}) so that I could do

$thisone->{'bit1} = 'val1';
$thisone->{'bit2} = 'val2';

Which would make it more readable.

I have partly achieved this - the following code works
------------------------------------------------------------------------------------------------------------------------------
use strict;
use warnings;
use Data::Dumper;

my %tableinfo;

while(<DATA>)
{
chomp;
my($table, $tstamp, $value, $morestuff, $yetmore, $evenmore) =
split(/:/);

$tableinfo{$table}{total} += $value;

## Want to make this line more readable
$tableinfo{$table}{stats}{$tstamp}{value} = $value; ## simplify this
line

my $thisone = $tableinfo{$table}{stats}{$tstamp}; ## assign
shortcut
## Can't do $thisone->{value} = $value . Autovivification ?
$thisone->{morestuff} = $morestuff;
$thisone->{yetmore} = $yetmore;
$thisone->{evenmore} = $evenmore;

$tableinfo{$table}{total} += $value;

}
print Dumper \%tableinfo;

__DATA__
firstone:12345:11111:9999:ccc:vvv
secondone:16767:22222:8888:bbb:nnn
firstone:12367:33333:7777:zzz:qqq
firstone:12389:44444:6666:www:xxx
secondone:17878:555555:4444:ddd:ppp
thirdone:14545:66666:1111:qqq:lll
thirdone:15656:7777:aaaaa:aaaaa:zzzz
-------------------------------------------------------------------------------------------------------------------------------

However as you can see I have been unable to shorten the first
assignnment line (marked 'simplify this line').

I can't do the line marked 'assign shortcut' and then $thisone->{value}
= $value presumably because until $tableinfo{$table}{stats}{$tstamp}
has been autovivified in the first assignment it doesn't exist.

My real world structure has about 8 levels of nexting so I want to keep
it as readable as possible.

Any suggestions for the best way to do this ?

Thanks
 
X

xhoster

I have a very deep nested hash and I need to set a lot of values at one
of the lowest levels.
Eg if I wanted to do something like

$a{b}{c}{d}{e}{f}{'bit1} = 'val1';
$a{b}{c}{d}{e}{f}{'bit2} = 'val2';
........ etc etc
I'd like to be able to assign a variable (say $thisone) to the top
levels ($a{b}{c}{d}{e}{f}) so that I could do

$thisone->{'bit1} = 'val1';
$thisone->{'bit2} = 'val2';

Which would make it more readable.

....

You need to make $thisone an alias rather than copy to the hash value.

## generate loop that does nothing but make $thisone an alias
foreach my $thisone ( $tableinfo{$table}{stats}{$tstamp}) {
$thisone->{value} = $value ; ## now can do this
$thisone->{morestuff} = $morestuff;
$thisone->{yetmore} = $yetmore;
$thisone->{evenmore} = $evenmore;

};


Xho
 
P

Paul Lalli

I have a very deep nested hash and I need to set a lot of values at one
of the lowest levels.
Eg if I wanted to do something like

$a{b}{c}{d}{e}{f}{'bit1} = 'val1';
$a{b}{c}{d}{e}{f}{'bit2} = 'val2';
........ etc etc
I'd like to be able to assign a variable (say $thisone) to the top
levels ($a{b}{c}{d}{e}{f}) so that I could do

$thisone->{'bit1} = 'val1';
$thisone->{'bit2} = 'val2';

Which would make it more readable.

I have partly achieved this - the following code works
------------------------------------------------------------------------------------------------------------------------------
use strict;
use warnings;
use Data::Dumper;

my %tableinfo;

while(<DATA>)
{
chomp;
my($table, $tstamp, $value, $morestuff, $yetmore, $evenmore) =
split(/:/);

$tableinfo{$table}{total} += $value;

## Want to make this line more readable
$tableinfo{$table}{stats}{$tstamp}{value} = $value; ## simplify this
line

my $thisone = $tableinfo{$table}{stats}{$tstamp}; ## assign
shortcut
## Can't do $thisone->{value} = $value . Autovivification ?
$thisone->{morestuff} = $morestuff;
$thisone->{yetmore} = $yetmore;
$thisone->{evenmore} = $evenmore;

$tableinfo{$table}{total} += $value;

}
print Dumper \%tableinfo;

__DATA__
firstone:12345:11111:9999:ccc:vvv
secondone:16767:22222:8888:bbb:nnn
firstone:12367:33333:7777:zzz:qqq
firstone:12389:44444:6666:www:xxx
secondone:17878:555555:4444:ddd:ppp
thirdone:14545:66666:1111:qqq:lll
thirdone:15656:7777:aaaaa:aaaaa:zzzz
-------------------------------------------------------------------------------------------------------------------------------

However as you can see I have been unable to shorten the first
assignnment line (marked 'simplify this line').

I can't do the line marked 'assign shortcut' and then $thisone->{value}
= $value presumably because until $tableinfo{$table}{stats}{$tstamp}
has been autovivified in the first assignment it doesn't exist.

I believe that assesment is correct. Reading a multi-level structure
does not involve autovivification, assigning to it does.
My real world structure has about 8 levels of nexting so I want to keep
it as readable as possible.

Any suggestions for the best way to do this ?

In your above case, you can do:
$tableinfo{$table}{stats}{$tstamp} = {};
rather than
$tableinfo{$table}{stats}{$tstamp}{value} = $value;
just to keep the symmetry of all the $thisone->{} statements intact,
but I don't know if that's still not readable enough for you.

Another suggestion might be to make %thisone an empty hash, then do
your deep assignments, and assign that back to the main structure
afterwords...

my %thisone = (value => $value, morestuff => $morestuff,
yetmore => $yetmore, evenmore=> $evenmore);
$tableinfo{$table}{stats}{$tstamp} = \%thisone;

Again the increased readability of that is debateable.

Paul Lalli
 
P

Paul Lalli

Jim said:
You want to assign a reference to $thisone (untested):

Please consider testing in the future. Really wouldn't have taken that
long...
my $thisone = \$tableinfo{$table}{stats}{$tstamp};

$thisone is now a reference to the undefined value.
Should work now.

No it shouldn't. Now you get:
Not a HASH reference at ./clpm.pl line 19, <DATA> line 1.

(Modified code pasted below for verification purposes)

Paul Lalli

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

my %tableinfo;

while(<DATA>){
chomp;
my($table, $tstamp, $value, $morestuff, $yetmore, $evenmore) =
split(/:/);

$tableinfo{$table}{total} += $value;

## Want to make this line more readable
# $tableinfo{$table}{stats}{$tstamp}{value} = $value; ## simplify
this line

## Can't do $thisone->{value} = $value . Autovivification ?
my $thisone = \$tableinfo{$table}{stats}{$tstamp};
$thisone->{value} = $value;
$thisone->{morestuff} = $morestuff;
$thisone->{yetmore} = $yetmore;
$thisone->{evenmore} = $evenmore;

$tableinfo{$table}{total} += $value;

}

print Dumper \%tableinfo;

__DATA__
firstone:12345:11111:9999:ccc:vvv
secondone:16767:22222:8888:bbb:nnn
firstone:12367:33333:7777:zzz:qqq
firstone:12389:44444:6666:www:xxx
secondone:17878:555555:4444:ddd:ppp
thirdone:14545:66666:1111:qqq:lll
thirdone:15656:7777:aaaaa:aaaaa:zzzz
 
B

Brian McCauley

Tim said:
my $thisone = ( $tableinfo{$table}{stats}{$tstamp} ||= {} );
$thisone->{value} = $value;

There's nothing wrong with that idiom and it's the one I most often use
but you can also use some others (some of which have been mentioned
elsewhere in this thread already).

my $thisone = \$tableinfo{$table}{stats}{$tstamp};
$$thisone->{value} = $value;


my $thisone = \%{$tableinfo{$table}{stats}{$tstamp}};
$thisone->{value} = $value;


for my $thisone ( $tableinfo{$table}{stats}{$tstamp} ) {
$thisone->{value} = $value;
}
 
U

Uri Guttman

PL> I believe that assesment is correct. Reading a multi-level structure
PL> does not involve autovivification, assigning to it does.

you have it wrong there. if you read a deep but nonexisted slot (meaning
parent slots are missing) perl will autovivify all the parents. the
final slot itself doesn't get autovivified. and exists() doesn't handle
that as well.

OP: read my autovivification tutorial:

http://sysarch.com/Perl/autoviv.txt

uri
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top