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:
How to print the multilevel hash sequentially

 



Tejas
User

Nov 27, 2014, 3:26 AM

Post #1 of 25 (10144 views)
How to print the multilevel hash sequentially Can't Post

Below is the code snippet

Code
 

my %First_hash =
(
1 => "Desc1",
2 => "Desc2",
3 => "Desc3",
4 => "Desc4",
);


my %Second_hash =
(
1 => "Desc1",
2 => "Desc2",
3 => "Desc3",
4 => "Desc4",
);

my %third_hash = (
1 => "Desc1",
2 => "Desc2",
3 => "Desc3",
4 => "Desc4",
);




my %final_hash ;
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{1}} = one;
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{2}} = two;
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{3}} = three;
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{4}} = four;

foreach my $l1 ( keys %final_hash) {
foreach my $l2 ( keys %{$final_hash{$l1}}) {
foreach my $l3 ( keys %{$final_hash{$l1}{$l2}}) {
print "$l1,$l2,$l3,$final_hash{$l1}{$l2}{$l3} \n";
}
}
}


Outptut

Quote
Desc1,Desc1,Desc1,one
Desc1,Desc1,Desc4,four
Desc1,Desc1,Desc2,two
Desc1,Desc1,Desc3,three


Expected Output

Quote
Desc1,Desc1,Desc1,one
Desc1,Desc1,Desc2,two
Desc1,Desc1,Desc3,three
Desc1,Desc1,Desc4,four


How could the hash and the code be rebuild to make this sequence happen ?
There would be no issue if the below code is also changed


Code
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{1}} = one; 
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{2}} = two;
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{3}} = three;
$final_hash{$First_hash{1}} {$Second_hash{1}} {$third_hash{4}} = four;


Only Reason i ve given keys as 1,2,3,4 is because i thought the keys are sorted by me as 1234 and are in sequence, it ll be printed in sequence
But that doesnt seem to work


Tejas
User

Nov 27, 2014, 3:36 AM

Post #2 of 25 (10143 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Below code is definitely working but the output doesnt have description in it , i.e my final value is being printed in Sequence but the keys should nt be numbers

Code
        my %First_hash = 
(
"Desc1" => 1 ,
"Desc2" => 2 ,
"Desc3" => 3 ,
"Desc4" => 4 ,
);


my %Second_hash =
(
"Desc1" => 1 ,
"Desc2" => 2 ,
"Desc3" => 3 ,
"Desc4" => 4 ,
);

my %third_hash = (
"Desc1" => 1 ,
"Desc2" => 2 ,
"Desc3" => 3 ,
"Desc4" => 4 ,
);


my %final_hash ;
$final_hash{$First_hash{"Desc1"}} {$Second_hash{"Desc1"}} {$third_hash{"Desc1"}} = one;
$final_hash{$First_hash{"Desc1"}} {$Second_hash{"Desc1"}} {$third_hash{"Desc2"}} = two;
$final_hash{$First_hash{"Desc1"}} {$Second_hash{"Desc1"}} {$third_hash{"Desc3"}}= three;
$final_hash{$First_hash{"Desc1"}} {$Second_hash{"Desc1"}} {$third_hash{"Desc4"}}= four;


foreach my $l1 ( sort keys %final_hash) {
foreach my $l2 ( sort keys %{$final_hash{$l1}}) {
foreach my $l3 ( sort keys %{$final_hash{$l1}{$l2}}) {
print "$l1,$l2,$l3,$final_hash{$l1}{$l2}{$l3} \n";
}
}
}


Output

1,1,1,one
1,1,2,two
1,1,3,three
1,1,4,four

I have made the values as number sequence but still it s not printing the data sequentially

Desired Output
Desc1,Desc1,Desc1,one
Desc1,Desc1,Desc2,two
Desc1,Desc1,Desc3,three
Desc1,Desc1,Desc4,four


The data should be in the order..
So that the keys get sorted and we do not miss the order

Quote
Please note that the numbers are given as key or value in my two approaches to print the descriptions sequentially ,we can intercahage it to a key or value in a hash
Also , the descriptin here are just dummy, they can be in any alphabetical order , but the number thats assigned to it would be the sequence
(Desc => 1 or 1 => Desc )
We have to print the description as per the sequence given in hash

Hope iam clear :)
Thanks
Tejas


(This post was edited by Tejas on Nov 27, 2014, 6:12 AM)


BillKSmith
Veteran

Nov 27, 2014, 6:31 AM

Post #3 of 25 (10135 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Hashes are never sorted.

Quote
Hashes are unordered collections of scalar values indexed by their associated string key.

From the fist paragraph of perldata.


You are in control of the order in your output.
Refer to the FAQ: perloc -q "sort a hash"
Good Luck,
Bill


Tejas
User

Nov 27, 2014, 6:35 AM

Post #4 of 25 (10133 views)
Re: [BillKSmith] How to print the multilevel hash sequentially [In reply to] Can't Post

Yes but iam getting the values
And I need the descrition of the keys
As specified in the desired output

Well , in my second post the order is sequential
But iam getting the values of the hash
But I need its keys

Ex I need desc1 instead of 1

Thanks
Tejas


(This post was edited by Tejas on Nov 27, 2014, 6:37 AM)


BillKSmith
Veteran

Nov 27, 2014, 7:29 AM

Post #5 of 25 (10131 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Your first approach is probably better. Just sort the keys the same way that you do in the second. For this example, the default sort will work. In the general case, you will have to write a sort block to do the right thing. Did you read the FAQ?
Good Luck,
Bill


Tejas
User

Nov 27, 2014, 9:01 AM

Post #6 of 25 (10125 views)
Re: [BillKSmith] How to print the multilevel hash sequentially [In reply to] Can't Post

Yes, i just gone through it

Code
foreach $key (sort { $hash{$b} <=> $hash{$a} } keys %hash)



But not sure how to write it for multi level hash.
My hash is 7 levels deep

Thanks
Tejas


FishMonger
Veteran / Moderator

Nov 27, 2014, 9:09 AM

Post #7 of 25 (10123 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

If you're using sequential numbers for hash keys to maintain order, then that's a clear indication you're using the wrong data structure. You should use an array. In this case more like an AoHoHoHoHoH


(This post was edited by FishMonger on Nov 27, 2014, 9:11 AM)


Tejas
User

Nov 27, 2014, 9:11 AM

Post #8 of 25 (10121 views)
Re: [FishMonger] How to print the multilevel hash sequentially [In reply to] Can't Post

And that cant be acheived using anyways ?


FishMonger
Veteran / Moderator

Nov 27, 2014, 9:14 AM

Post #9 of 25 (10116 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post


In Reply To
And that cant be acheived using anyways ?

I'm not sure what you mean by that.


Tejas
User

Nov 27, 2014, 9:17 AM

Post #10 of 25 (10113 views)
Re: [FishMonger] How to print the multilevel hash sequentially [In reply to] Can't Post

Hey

Cant that be acheived using hashes.
Well, I under stand the it would be a bad design using a hash ,
but can the end result be acheived or can that be tweaked.

And also, can u please explain how can i replace this with array implementation

Thanks
Tejas


FishMonger
Veteran / Moderator

Nov 27, 2014, 9:36 AM

Post #11 of 25 (10102 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Yes, it can be achieved using a hash structure, but that would be questionable design in this case. I'm late for a thanksgiving party so I can't post the array of hashes example until tomorrow.


Tejas
User

Nov 27, 2014, 9:37 AM

Post #12 of 25 (10100 views)
Re: [FishMonger] How to print the multilevel hash sequentially [In reply to] Can't Post

Sure

Please do post if u find time.

Thanks
Tejas


FishMonger
Veteran / Moderator

Nov 28, 2014, 8:54 AM

Post #13 of 25 (9980 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Please post a sample of your real data and explain what you need to do with it. Based on your posted fictitious data, I'd do that as a single level array as a first choice and a flat (single level) hash has a second choice.


Tejas
User

Nov 28, 2014, 9:24 AM

Post #14 of 25 (9974 views)
Re: [FishMonger] How to print the multilevel hash sequentially [In reply to] Can't Post

Hi Laurent

Here is the sample code


Code
my %business_hash = (   
1=>"Provisional",
2=>"Non provisional",
#There are many of these

) ;


my %business_type = (
1 => "Revenue",
2 => "Non Rev",
3 => "Settlements",
) ;

my %Automated_Manual = (
1 => "Automated",
2 => "Manual",

);

my %my_source1 = (
1 => "MSL" ,
2 => "Unicorn" ,
3 => "Spread" ,
4 => "TCS" ,
5 => "FRONT" ,

);


my %source_system = (
1 => "Herd" ,
2 => "HReturns" ,
3 => "Moon" ,
4 => "Revise" ,
#There are hundreds of them
);
my %description = (
1=>"Provisional Sales",
2=>"Provisional Sales (none)",
3=>"Non-provisional Sales",
4=>" On Demand Sales",
#There are hundreds of them
);



my %final_hash ;

#Here we are hardcoding according to the requirement andf we print it below
$data_hash{1}{1}{1}{1}{1}{1} = 14 ;

$data_hash{1}{1}{1}{1}{1}{4} = 14 ;
$data_hash{1}{1}{1}{1}{2}{1} = 14 ;
$data_hash{1}{1}{1}{1}{3}{1} = 14 ;
$data_hash{1}{1}{1}{1}{2}{3} = 14 ;

$data_hash{1}{1}{1}{1}{1}{2} = 14 ;
$data_hash{1}{1}{1}{1}{1}{3} = 14 ;

foreach 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}}) {
print "$business_hash{$l1},$business_type{$l2},$Automated_Manual{$l3},$my_source1{$l4},$source_system{$l5},$description{$l6} => $data_hash{$l1}{$l2}{$l3}{$l4}{$l5}{$l6} \n"
}}}}}}



Code output

Quote
Provisional,Revenue,Automated,MSL,Herd,Provisional Sales => 14
Provisional,Revenue,Automated,MSL,Herd,Provisional Sales (none) => 14
Provisional,Non Rev,Automated,MSL,Herd,Non-provisional Sales => 14
Provisional,Non Rev,Automated,MSL,Herd, On Demand Sales => 14
Provisional,Non Rev,Automated,MSL,HReturns,Provisional Sales => 14
Provisional,Non Rev,Automated,MSL,HReturns,Non-provisional Sales => 14
Provisional,Non Rev,Automated,MSL,Moon,Provisional Sales => 14

And the same is expected

Here i had to build the hash with numbers as i want them in the order which i have deslared in a hash.

Is there a simple way ,as u have specified yesterday.
I hope its clear


Laurent_R
Veteran / Moderator

Nov 28, 2014, 10:48 AM

Post #15 of 25 (9958 views)
Re: [FishMonger] How to print the multilevel hash sequentially [In reply to] Can't Post

Yes, using an AoAoAoA (array or arrays of ...) would probably be simpler, because there would be no need to sort the data.

No time to give an example now, but I will try later.


FishMonger
Veteran / Moderator

Nov 28, 2014, 12:00 PM

Post #16 of 25 (9954 views)
Re: [Laurent_R] How to print the multilevel hash sequentially [In reply to] Can't Post

It appears to me that the OP has presented us with an XY problem and my attempt to gain more insight into the real problem has so far failed.


Laurent_R
Veteran / Moderator

Nov 28, 2014, 3:40 PM

Post #17 of 25 (9944 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

First, one comment about your code:


Code
my %final_hash ;  

#Here we are hardcoding according to the requirement andf we print it below
$data_hash{1}{1}{1}{1}{1}{1} = 14 ;


You declare %final_hash and use %data_hash. You're obviously not using the:

Code
use strict; 
use warnings;

pragmas, although you have been repeatedly told on this very forum and by several different persons that you should, at least for any script having more than one line.

It seems that you did not really believed FishMonger that using an AoAoA... was possible instead of a HoHoH...

This is en example, using exactly your algorithm, just changing nested hashes into nested arrays:


Code
use strict; 
use warnings;

my @business_array = qw(Provisional Non_provisional);
my @business_type = qw ( Revenue Non_Rev Settlements);
my @Automated_Manual = qw( Automated Manual);
my @my_source1 = qw ( MSL Unicorn Spread TCS FRONT);
my @source_system = qw ( Herd HReturns Moon Revise );
my @description = ( "Provisional Sales", "Provisional Sales (none)", "Non-provisional Sales", "On Demand Sales");


my @data_array ;

#Here we are hardcoding according to the requirement and we print it below
$data_array[0][0][0][0][0][0] = 14 ;
$data_array[0][0][0][0][0][3] = 14 ;
$data_array[0][0][0][0][1][0] = 14 ;
$data_array[0][0][0][0][2][0] = 14 ;
$data_array[0][0][0][0][1][2] = 14 ;
$data_array[0][0][0][0][0][1] = 14 ;
$data_array[0][0][0][0][0][2] = 14 ;


foreach my $l1 (0..$#data_array) {
foreach my $l2 (0..$#{$data_array[$l1]}) {
foreach my $l3 (0..$#{$data_array[$l1][$l2]}) {
foreach my $l4 (0..$#{$data_array[$l1][$l2][$l3]}) {
foreach my $l5 (0..$#{$data_array[$l1][$l2][$l3][$l4]}) {
foreach my $l6 (0..$#{$data_array[$l1][$l2][$l3][$l4][$l5]}) {
print "$business_array[$l1],$business_type[$l2],$Automated_Manual[$l3],$my_source1[$l4]",
"$source_system[$l5],$description[$l6] => $data_array[$l1][$l2][$l3][$l4][$l5][$l6] \n"
}
}
}
}
}
}


As you can see, the code is quite a bit shorter and simpler.

Now executing the above script yields more or less the same output as yours, except for a little quite interesting surprise:


Code
Provisional,Revenue,Automated,MSLHerd,Provisional Sales => 14 
Provisional,Revenue,Automated,MSLHerd,Provisional Sales (none) => 14
Provisional,Revenue,Automated,MSLHerd,Non-provisional Sales => 14
Provisional,Revenue,Automated,MSLHerd,On Demand Sales => 14
Provisional,Revenue,Automated,MSLHReturns,Provisional Sales => 14
Use of uninitialized value in concatenation (.) or string at tejas.pl line 31.
Provisional,Revenue,Automated,MSLHReturns,Provisional Sales (none) =>
Provisional,Revenue,Automated,MSLHReturns,Non-provisional Sales => 14
Provisional,Revenue,Automated,MSLMoon,Provisional Sales => 14

My output is the same as yours, except that I have these two additional lines:

Code
Use of uninitialized value in concatenation (.) or string at tejas.pl line 31. 
Provisional,Revenue,Automated,MSLHReturns,Provisional Sales (none) =>

This is likely to exhibit a bug in your code, which fails to initialize:

Code
$data_hash{1}{1}{1}{1}{2}{2} = ??;

which is most likely to be wrong.

Adding this line to my code:

Code
$data_array[0][0][0][0][1][1] = 14 ;

removes the warning and print the line correctly:

Code
Provisional,Revenue,Automated,MSLHReturns,Provisional Sales (none) => 14

Just in case you voluntarily did not initialize $data_hash{1}{1}{1}{1}{2}{2} (which I would find a little hard to believe), then you would have to add a conditional in my array solution, in order to do print the line only if the value is defined.

This was just to show how to do almost exactly what you do with nested arrays, making it simpler because you don't have to sort repeatedly the data.

Now, the real important point I want to make here is that your solution is very complicated, probably inefficient and, if you have a lot more data as you said, extremely labor intensive. I do not have the wider picture of what you are trying to do with this program, so it is impossible for me to offer a better alternative at this point, but there are a couple of things that ring a bell to me that something must be wrong in what you are doing.

- Having six levels of nestedness in your data structure is a sign that something is probably wrong. That might be OK for a NASA or Star War program making extremely complicated things, it seems to be overkill for a simple accounting application (if I understand correctly, that's what you are doing). Although I hate to say that (because I have seen far too many times people on Forums recommending that for terribly wrong reasons, especially when it comes to performance reasons, although a hash can be many order of magnitudes faster), using a database would probably make much more sense for managing the data complexity.

- Hardcoding your hashes the way you do would be OK if you had only a dozen pieces of data or so, or maybe twenty, but you say that you have hundreds. There must be a better way involving much less typing and much less leeway for errors. Failing a better solution, I would at the very least store the data of your hashes in a separate CSV or possibly XML file, rather than hardcoding it within the program. The good thing about using a separate file is that someone not able to use Perl will still be able provide the data in a usable format. Or, as already mentionned, a database.

- Hardcoding the final %datahash is even much worse. Don't do that, it's horrible, it is a pure calamity. Put that data in a separate file (or, again, in a database table).

Now, given the complexity of what you're doing, I suggested repeatedly a database (although, as I already said, I am no great fan of that solution when it may not be needed). That may very well be the simplest solution in your case. But I would tend to think that it is not needed and that your whole problem could be solved in a much simpler way.

But, again, you did not give us enough information on the bigger picture.

I think that FishMonger is most probably correct when he is speaking of a XY problem. You have a functional or business problem, you have found your own technical way to more or less solve it, but you encounter difficulties with your solution, so you are asking for technical help on how to make your solution work. But there are a lot of indications that your solution is probably not the best. Please explain what you are really trying to do, rather than why the way you are trying to do it does not give you the desired result, we might come up with something much easier to implement.


(This post was edited by Laurent_R on Nov 28, 2014, 3:49 PM)


Tejas
User

Nov 28, 2014, 8:06 PM

Post #18 of 25 (9931 views)
Re: [Laurent_R] How to print the multilevel hash sequentially [In reply to] Can't Post

Hi

I understand that an array or a hash would make life hard for me tocode
It's real labor intensive .
The precise requirement here is
We have an excel sheet and the data in that excel sheet is
Our final hash
Our excel file contains data business wise and that what the first two hashes do
Later on, the final hash we have are the values available in each row
Each key of the nested hash is a cell value
So we really need not have a csv as we have an excel sheet, but we have to save all the data in the code rather than a extra file.
Even I feel thT this solution will not be perfect and having an extra file would be easy.
I will also look at the xml approach u have suggested .
And the only difference in array and hash is auto indexing and probably for the weird big hash I'm building , traversal would be slow as o see lots of collisions in the keys internally in the hash
And tht would nt be an issue in arrays
Thanks
Tejas


Laurent_R
Veteran / Moderator

Nov 29, 2014, 3:12 AM

Post #19 of 25 (9922 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Why don't you use a speadsheet/Excel Perl module to read the data directly from the Excel sheet? That would most probably be much easier.


Quote
traversal would be slow


Don't worry too much about that. Hashes are pretty fast, you won't have any performance problem unless your data is really very large and/or your program REALLY time critical. When I said that your solution appeared to be "inefficient", I did not mean in terms of time performance or execution speed, but more in terms of the time and complexity to code all your data structures.


Tejas
User

Nov 29, 2014, 8:53 AM

Post #20 of 25 (9915 views)
Re: [Laurent_R] How to print the multilevel hash sequentially [In reply to] Can't Post

Hi
I have already done that and tht was way easier than all this
But the client wanted us to have it in a program rather tha an extra input file
Due to which we had to do this laborious work.
I really understand the concerns of This approach
And would want to get rid of this .


Thanks
Teja


Laurent_R
Veteran / Moderator

Nov 29, 2014, 12:03 PM

Post #21 of 25 (9898 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Well, yes, I know, clients are sometimes a bit silly. If you really can't use a separate file, at least put the data in an easy to process format in the __DATA__ section of your program.


Tejas
User

Nov 30, 2014, 2:03 AM

Post #22 of 25 (9760 views)
Re: [Laurent_R] How to print the multilevel hash sequentially [In reply to] Can't Post

Yes
I will try to do this
It would be a lot easier.


Thanks
Tejas


Tejas
User

Nov 30, 2014, 6:09 AM

Post #23 of 25 (9751 views)
Re: [Laurent_R] How to print the multilevel hash sequentially [In reply to] Can't Post

Hi Laurent

Can we have all these 2000 line csv file in the data block

Thanks
Tejas


Laurent_R
Veteran / Moderator

Nov 30, 2014, 10:16 AM

Post #24 of 25 (9742 views)
Re: [Tejas] How to print the multilevel hash sequentially [In reply to] Can't Post

Yes, as far as I know, you can put as much data as you want in the __DATA__ section at the end of your program.


Tejas
User

Dec 3, 2014, 9:48 AM

Post #25 of 25 (9090 views)
Re: [Laurent_R] How to print the multilevel hash sequentially [In reply to] Can't Post

Thanks

Working on it

 
 


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

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