packetstormer has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks

My eyes are bleeing (figuratively!) trying to create an anoymous hash and populate it, within a while loop. A sample of the data:

20150120172947|94|AD-PC40|Area 1|1| | | |4|0| |K-1|L 20150120172947|95|AD-PC41|Area 1|6| | | |0|0| |K-1|L 20150120172947|101|AD-PC46|Area 1|1| | | |0|0| |K-1|L 20150120172947|103|AD-PC49|Area 1|1| | | |0|0| |K-1|L 20150120172947|46|ATECH-PC02|Area 2|1| | | |4|0| |K-1|L 20150120172947|129|ENFTPC|Area 3|268435462| | | |0|0| |K-1|L 20150120172947|7|EX-PC04|Area 4|1| | | |4|0| |K-1|L 20150120172947|8|EX-PC05|Area 5|1| | | |4|0| |K-1|L 20150120172947|9|EX-PC06|Area 5|1| | | |4|0| |K-1|L 20150120172947|12|EX-PC09|Area 5|1| | | |4|0| |K-1|L 20150120172947|100|EX-PC10|Area 5|1| | | |4|0| |K-1|L 20150120172947|13|EX-PC11|Area 5|1| | | |4|0| |K-1|L 20150120172947|14|EX-PC12|Area 5|1| | | |4|0| |K-1|L 20150120172948|15|EX-PC13|Area 5|1| | | |4|0| |K-1|L 20150120172948|16|EX-PC14|Area 5|1| | | |4|0| |K-1|L 20150120172948|105|JR-AT-PC01|Area 6|6| | | |0|0| |K-1|L 20150120172948|106|JR-AT-PC02|Area 6|6| | | |0|0| |K-1|L 20150120172948|JR-PC02|Area 6|1| | | |4|0| |K-1|L 20150120172948|86|JR-PC04|Area 6|1| | | |4|0| |K-1|L 20150120172948|109|JR-PC05|Area 6|1| | | |4|0| |K-1|L 20150120172948|114|JR-PC06|Area 6|1| | | |4|0| |K-1|L 20150120172948|116|JR-PC07|Area 6|268435458| | | |0|155| |K0|L 20150120172948|112|JR-PC10|Area 6|268435461| | | |4|0| |K-1|L 20150120172948|110|JR-PC13|Area 6|6| | | |0|0| |K-1|L

I am trying to iterate down and for each unique value in the 4th column create a hash. Within that hash, add the line iteself (either in an arrayref or a further hashref). My problem is that I can't figure out how to preserve the hash. I would like to write this so the code can pick up any "Area" but I know it would be much easier to create the static hashes first like this

my ($area1,$area2,$area4); while (<FH>) { my @r = split /\|/,$_; if ($r[3] eq "Area 1") {$area1->{$r[2]} = $_} if ($r[3] eq "Area 4") {$area4->{$r[2]} = $_} } print Dumper $area1,$area4 $VAR1 = \{ 'AD-PC46' => '20150120172947|101|AD-PC46|Area 1|1| | | |0| +0| |K-1|L ', 'AD-PC41' => '20150120172947|95|AD-PC41|Area 1|6| | | |0|0 +| |K-1|L ', 'AD-PC49' => '20150120172947|103|AD-PC49|Area 1|1| | | |0| +0| |K-1|L ', 'AD-PC40' => '20150120172947|94|AD-PC40|Area 1|1| | | |4|0 +| |K-1|L ' }; $VAR2 = \{ 'EX-PC04' => '20150120172947|7|EX-PC04|Area 4|1| | | |4|0| + |K-1|L ' };

But, I would like to not define any hash names and create them based on the value in the 4th field. This way, the code could drop onto any install and I wouldn't have to read an cfg file of area values etc.

Does anyone have any "tricks" or ideas how I might go about this? Thanks

Replies are listed 'Best First'.
Re: Anonymous hash of arrays
by choroba (Cardinal) on Jan 21, 2015 at 09:45 UTC
    Use a hash of hashes (HoH):
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hash; while (<>) { my @items = split /\|/; $hash{ $items[3] }{ $items[2] } = [ @items[0, 1, 4 .. $#items] ]; } print Dumper \%hash;
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Thanks, this is exactly what I need

Re: Anonymous hash of arrays
by jellisii2 (Hermit) on Jan 21, 2015 at 12:56 UTC
    Have you looked at alternative solutions, like using Tie::Handle::CSV to handle the data? While I don't know your use case, the data seems well constructed to be managed like that.