CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Can we use Dumper to define hash of hash of hashes , rather than we manually creating it.

 



Tejas
User

Jan 8, 2015, 10:41 AM

Post #1 of 9 (2362 views)
Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. Can't Post

Hi

First 5 Values are keys , rest should be a single value with delimiter ,if the keys are same, they have to be a part of array of values

Quote
Input
A,B,C,D,E,F,G,H
A,B,C,D,E,I,J,K
B,C,D,E,F,,F
X,Y,Z,A,B,,P
X,Y,Z,A,B,Q,P,R




Quote
OUTPUT
$hash{A}{B}{C}{D}{E} = ["F-G-H" , "I-J-K" ] ;
$hash{B}{C}{D}{E}{F} = ["-F"];
$hash{X}{Y}{Z}{A}{B} = ["-P","Q-P-R"]




Quote
code

my %hash;
while<FILE> {
my ($key1,$key2,$key3,$key4,$key5,$val1,$val2,$val3) = (split /,/,$line)
print OUTFILE "$hash{$key1}{$key2}{$key3}{$key4} = [$val1-$val2-$val3]\n"
}


But , this doesnt creat an array of values ,like the first line of output
Or i can use dumper for this to be done, not sure how

Also, i have pasted the untested code, just for the understanding of the requirement
I have a very large file with 350 lines and , they have to be in a hash .
So rather than me creating it manually , can a code do it.
But in th eway i want it ..(Hash of Hash of hash of hash to array )

something like this


Code
   
let's say @row_list contains each line ,

my $row_str = join ';', @row_list;
push @$list, \@row_list;
open my $out_fh, '>', $output or die "cannot open '$output': $!";
print $out_fh Dumper($list);
close $out_fh;


i can use a dumber to create an array of all the values, but i need (Hash of Hash of hash of hash to array )


Code
use strict; 
use warnings;
use Data::Dumper;

my %hash;
$hash{""}{"01"}{"14"} = ["OTC-web"];
$hash{"04"}{"01"}{"14"} = ["CTO-"];
$hash{"04"}{"01"}{"15"} = ["BAC-uyu"];

$hash{""}{"03"}{"19"} = ["-OTC"];

print Dumper (\%hash);


output

Quote
$VAR1 = {
'' => {
'01' => {
'14' => [
'OTC-web'
]
},
'03' => {
'19' => [
'-OTC'
]
}
},
'04' => {
'01' => {
'15' => [
'BAC-uyu'
],
'14' => [
'CTO-'
]
}
}
};



(This post was edited by Tejas on Jan 8, 2015, 10:44 AM)


FishMonger
Veteran / Moderator

Jan 8, 2015, 12:59 PM

Post #2 of 9 (2354 views)
Re: [Tejas] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

Why use a HoH instead of a simpler hash with a composite key?


Code
use strict; 
use warnings;
use Data::Dumper;

my %HoH;
my %hash;

while (<DATA>) {
chomp;
my (@vals) = split /,/;
$HoH{$vals[0]}{$vals[1]}{$vals[2]}{$vals[3]}{$vals[4]} = [ @vals[5..$#vals] ];

my $key = join '-', @vals[0..4];
$hash{$key} = [ @vals[5..$#vals] ];
}

print Dumper \%HoH, \%hash;

__DATA__
A,B,C,D,E,F,G,H
A,B,C,D,E,I,J,K
B,C,D,E,F,,F
X,Y,Z,A,B,,P
X,Y,Z,A,B,Q,P,R



Code
$VAR1 = { 
'A' => {
'B' => {
'C' => {
'D' => {
'E' => [
'I',
'J',
'K'
]
}
}
}
},
'X' => {
'Y' => {
'Z' => {
'A' => {
'B' => [
'Q',
'P',
'R'
]
}
}
}
},
'B' => {
'C' => {
'D' => {
'E' => {
'F' => [
'',
'F'
]
}
}
}
}
};
$VAR2 = {
'A-B-C-D-E' => [
'I',
'J',
'K'
],
'X-Y-Z-A-B' => [
'Q',
'P',
'R'
],
'B-C-D-E-F' => [
'',
'F'
]
};



Zhris
Enthusiast

Jan 8, 2015, 4:32 PM

Post #3 of 9 (2349 views)
Re: [FishMonger] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

Minor improvement to suit OP's expected output of "hash of hash of hash of hash of hash of array" by appending rather than overwriting:


Code
$HoH{$vals[0]}{$vals[1]}{$vals[2]}{$vals[3]}{$vals[4]} = [ @vals[5..$#vals] ]; 
push @{$HoH{$vals[0]}{$vals[1]}{$vals[2]}{$vals[3]}{$vals[4]}}, [ @vals[5..$#vals] ];

# and

$hash{$key} = [ @vals[5..$#vals] ];
push @{$hash{$key}}, [ @vals[5..$#vals] ];


Regards,

Chris


(This post was edited by Zhris on Jan 8, 2015, 4:33 PM)


Tejas
User

Jan 9, 2015, 9:16 AM

Post #4 of 9 (2327 views)
Re: [FishMonger] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

Hi FishMonger

I dont think tht will work for the requirement i have.
I have just asked the doubt that is part of my requirements.

Let me explain the full details.
The data is still dummy


Quote
So , The Original Requirement and the reason behind me wanting to generate the definintion of hash through script is metioned in code below

All these are examples and they relate to my original requirement, so descriptions here have similar values, but in reality each description each key is a unique and a different value.



Code
 
my %description1 = (1=>abc1,2=>xyz1,3=>PQR1,4=>Blah1);
my %description2 = (1=>abc2,2=>xyz2,3=>PQR2,4=>Blah2);
my %description3 = (111=>abc3,112=>xyz3,113=>PQR3,114=>Blah3);
my %description4 = (1=>abc4,2=>xyz4,3=>PQR4,4=>Blah4);
my %description5 = (1=>abc5,2=>xyz5,3=>PQR5,4=>Blah5);
my %description6 = (1=>abc6,2=>xyz6,3=>PQR6,4=>Blah6);
my %description7 = (1=>abc7,2=>xyz7,3=>PQR7,4=>Blah7);


my %data_hash ;
$data_hash{1}{1}{111}{1}{1}{1}{1} = ["04-MSL-1"];
$data_hash{1}{1}{111}{1}{1}{1}{2} = ["04-MSL-47"];
$data_hash{1}{1}{111}{1}{1}{1}{3} = ["04-MSL-204"];
$data_hash{1}{1}{111}{1}{1}{1}{4} = [""];
$data_hash{1}{1}{111}{1}{1}{1}{5} = [""];
$data_hash{1}{1}{111}{1}{1}{1}{6} = [""];
$data_hash{1}{1}{111}{1}{1}{1}{7} = [""];
$data_hash{1}{1}{111}{1}{1}{1}{8} = [""];
$data_hash{1}{1}{111}{1}{1}{1}{9} = ["04-MSL-526"];
$data_hash{1}{1}{111}{1}{1}{1}{10} = ["04-MSL-68"];


Quote
Now these numbers would be printed sequentially and each key woule me matched with a hash which has description and there are 7 levels
i.e something like below.


Code
oreach my $l1 ( sort {$a <=> $b}keys %data_hash) { 
foreach my $l2 ( sort {$a <=> $b} keys %{$data_hash{$l1}}) {
foreach my $l3 ( sort {$a <=> $b} keys %{$data_hash{$l1}{$l2}}) {
foreach my $l4 ( sort {$a <=> $b} keys %{$data_hash{$l1}{$l2}{$l3}}) {
foreach my $l5 ( sort {$a <=> $b} keys %{$data_hash{$l1}{$l2}{$l3}{$l4}}) {
foreach my $l6 ( sort {$a <=> $b} keys %{$data_hash{$l1}{$l2}{$l3}{$l4}{$l5}}) {
foreach my $l7 (sort {$a <=> $b} keys %{$data_hash{$l1}{$l2}{$l3}{$l4}{$l5}{$l6}}) {

my @gl_data = ($description1{$l3},$description2{$l4},$description3{$l5},$description4{$l6});
my @sl_data = $data_hash{$l1}{$l2}{$l3}{$l4}{$l5}{$l6}{$l7};
print "@gl_data,@sl_data \n";
# print_to_excel (\@gl_data,\@sl_data);

}}}}}}}

#These hashes are not full in content.just for the purpose of understanding



Quote
Above is the way we are hardcodiing the hash with numbers correspoding to some description,which are decoded during print.

Now, Coming to the main motto behind this thread,
I have an input file with the descriptions

So that the print order is in my hands and the order is determined the data hash keys.
While i loop , it ll be in order(numerical).


abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,68
and this is hard coded as
$data_hash{1}{1}{111}{1}{3}{1}{4} = ["04-MSL-68"];

And we have tried to create hash of hash of hash to an array
This way i have lots of lines and i have to hard code a data hash with corresonding number keys.

And due to the same reason , i wanted the perl dumper to create the definition .
As i have lots and lots of lines , and they should be defined by dumper and shoiuld nt be literal values like we have initially tried, but should b ethe hash key
(number) to which this value is created
ex : my %description7 = (1=>abc7,2=>xyz7,3=>PQR7,4=>Blah7);
Though we have abc7 in the file, hash should have 1 and i will decode it to abc7 while prinitng it.



Now , all iam trying to do is
1. read the file with values
2. get the key from the descripion hash for the read value
3.Create a data hash with keys.
ex :
File data :
abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,68
abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,69
$data_hash{1}{1}{111}{1}{3}{1}{4} = ["04-MSL-68","04-MSL-69"];
Hope this is clear.


Thanks
Tejas


(This post was edited by Tejas on Jan 9, 2015, 9:38 AM)


FishMonger
Veteran / Moderator

Jan 9, 2015, 9:39 AM

Post #5 of 9 (2322 views)
Re: [Tejas] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

You need to use a database.

What you're doing here is so convoluted that I can't make out what you're really trying to accomplish or why a composite key wouldn't accomplish your goal. Maybe Chris has a better crystal ball than I and can figure out what you need.

Can you show a sample of real data and explain in clear terms (without this multidimensional hash) what you need to accomplish?


Tejas
User

Jan 9, 2015, 9:42 AM

Post #6 of 9 (2320 views)
Re: [FishMonger] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

well, i have a file with data something like this

abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,68
abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,69

and trying to create a hash out of this
which i read sequentially and write it to excel

This basically is a template ,which we are hardcoding in a hash and
as this template has to be printed as it is, we are using numbers


I will try and explin with real data if this is nt understandable


Thanks
Tejas


Tejas
User

Jan 9, 2015, 9:44 AM

Post #7 of 9 (2318 views)
Re: [FishMonger] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

And just for not confusing you, i ve directly asked waht i wanted.
1. Get the values from excel file or a csv file
2.Now for each value there is a key associated.
3. these jeys have to be a part of hash of hash

In short, above is waht iam trying to acheive

Thanks
Tejas


Zhris
Enthusiast

Jan 9, 2015, 2:32 PM

Post #8 of 9 (2309 views)
Re: [Tejas] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

Hi,

It appears you want to loop through the input data (csv format), the first 7 (number of description hashes) values should be used to create a nested hash and the last values should be joined and pushed to build the nested hash value(s). The values used for keys are actually looked up in your description hashes which correspond to each hash level.

Based on the data you provided and your sample output I have derived that the following may be sufficient, although very rough. I have modified your description hash to become a description array with 7 internal hashes, and switched the keys and values so that its easier to look up with:


Code
use strict; 
use warnings;
use Data::Dumper;

my @descriptions =
(
{ abc1=>1,xyz1=>2,PQR1=>3,Blah1=>4 },
{ abc2=>1,xyz2=>2,PQR2=>3,Blah2=>4 },
{ abc3=>111,xyz3=>112,PQR3=>113,Blah3=>114 },
{ abc4=>1,xyz4=>2,PQR4=>3,Blah4=>4 },
{ abc5=>1,xyz5=>2,PQR5=>3,Blah5=>4 },
{ abc6=>1,xyz6=>2,PQR6=>3,Blah6=>4 },
{ abc7=>1,xyz7=>2,PQR7=>3,Blah7=>4 },
);

my %data_hash;
while ( <DATA> )
{
chomp;

my @row = split /,/;

# Data::Diver might handle the below much cleaner.

my $ref = \%data_hash;
for ( 0 .. $#descriptions )
{
my $key = $descriptions[$_]->{$row[$_]};
$ref = $ref->{$key} ||= $_ == $#descriptions ? [ ] : { } ;
}
push @$ref, join '-', @row[@descriptions .. $#row];

}

print Dumper \%data_hash;

__DATA__
abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,68
abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,69


Code
$VAR1 = { 
'1' => {
'1' => {
'111' => {
'1' => {
'3' => {
'1' => {
'4' => [
'04-MSL-68',
'04-MSL-69'
]
}
}
}
}
}
}
};


With regards to the Data::Diver comment, you could instead build your hash using something like the following (untested):


Code
use Data::Diver qw/DiveVal/; 

my @keys = map { $descriptions[$_]->{$row[$_]} } 0 .. $#descriptions;
my $val = join '-', @row[@descriptions .. $#row];
DiveVal( \%data_hash, \( @keys ) ) = $val;


Regards,

Chris


(This post was edited by Zhris on Jan 9, 2015, 2:51 PM)


Zhris
Enthusiast

Jan 10, 2015, 5:53 AM

Post #9 of 9 (2284 views)
Re: [Zhris] Can we use Dumper to define hash of hash of hashes , rather than we manually creating it. [In reply to] Can't Post

After discussing on skype this morning, we have come up with a final but inevitably rough version. The following adjustments were made:

- description hashes key / vals had to be switched back, therefore now looking up keys from vals.
- OP quite literally wanted the output "$data_hash_b{1}{1}{111}{1}{3}{1}{4} = ["04-MSL-68", "04-MSL-69"];". Didn't get into too much detail as to why, i'm sure this is an xy problem. I used a modified set of rough undive functions I wrote a while back to achieve just this.


Code
use strict;  
use warnings;
use Data::Dumper;

my @descriptions =
(
{ 1=>'abc1',2=>'xyz1',3=>'PQR1',4=>'Blah1' },
{ 1=>'abc2',2=>'xyz2',3=>'PQR2',4=>'Blah2' },
{ 111=>'abc3',112=>'xyz3',113=>'PQR3',114=>'Blah3' },
{ 1=>'abc4',2=>'xyz4',3=>'PQR4',4=>'Blah4' },
{ 1=>'abc5',2=>'xyz5',3=>'PQR5',4=>'Blah5' },
{ 1=>'abc6',2=>'xyz6',3=>'PQR6',4=>'Blah6' },
{ 1=>'abc7',2=>'xyz7',3=>'PQR7',4=>'Blah7' },
);

my %data_hash;

while ( my $line = <DATA> )
{
$line =~ s/\s*$//;

my @row = split /,/, $line;

my $ref = \%data_hash;

for my $description_i ( 0 .. $#descriptions )
{
# better to use first.
my ( $key ) = grep { $descriptions[$description_i]->{$_} eq $row[$description_i] } keys %{$descriptions[$description_i]};

$ref = $ref->{$key} ||= $description_i == $#descriptions ? [ ] : { } ;
}

push @$ref, join '-', @row[@descriptions .. $#row];
}

my $data_list = undive( \%data_hash );

my $str = '';
for ( @$data_list )
{
$str .= '$data_hash_b{' . ( join '}{', @$_[0 .. $#{$_} - 1] ) . '} = ["' . ( join '", "', @{$_->[-1]} ) . "\"];\n";
}

my %data_hash_b;
eval $str;
print $str;
print Dumper \%data_hash_b;

sub undive # entry.
{
my ( $in ) = @_;

my $out = [ ];
my $selector = [ ];

undive_b( $in, $out, $selector ); # undive_b in.

return $out;
}

sub undive_b # tests ref type of in then iterates.
{
my ( $in, $out, $selector ) = @_;

if ( ref $in eq ref { } ) # in is hash.
{
undive_c( $out, $selector, $_, $in->{$_} ) for ( sort { $a <=> $b } keys %$in ); # undive_c for each key in hash.
}
else
{
die 'unsupported ref type';
}

return 1;
}

sub undive_c # tests if val is ref then decides how to proceed.
{
my ( $out, $selector, $selectee, $val ) = @_;

if ( ref $val eq ref { } ) # val is hash ref.
{
undive_b( $val, $out, [ @$selector, $selectee ] ); # undive_b val.
}
else # val is not hash ref i.e. end of the line.
{
push @$out, [ @$selector, $selectee, $val ]; # push to out.
}

return 1;
}

__DATA__
abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,68
abc1,abc2,abc3,abc4,PQR5,abc6,Blah7,04,MSL,69


Code
$data_hash_b{1}{1}{111}{1}{3}{1}{4} = ["04-MSL-68", "04-MSL-69"]; 
$VAR1 = {
'1' => {
'1' => {
'111' => {
'1' => {
'3' => {
'1' => {
'4' => [
'04-MSL-68',
'04-MSL-69'
]
}
}
}
}
}
}
};


Chris


(This post was edited by Zhris on Jan 10, 2015, 5:55 AM)

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives