Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Multidimensional Hash implementation/usage

by subhankar (Novice)
on Sep 17, 2007 at 06:24 UTC ( #639345=perlquestion: print w/ replies, xml ) Need Help??
subhankar has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,
I am a newbie to Perl and I have been trying to work with it since the last few days.

There's an awk script, which works but I have been told to use Perl to rewrite the same as we need Perl's formatting capabilities. I converted the AWK script to Perl using a2p. The code :

#!/usr/perl5/5.6.1/bin/perl $[ = 1; # set array base to 1 $FS = '|'; ##SUBSEP = "|"; while (<>) { ($Fld1,$Fld2,$Fld3,$Fld4,$Fld5,$Fld6,$Fld7,$Fld8,$Fld9,$Fld10,$Fld +11,$Fld12,$Fld13,$Fld14,$Fld15,$Fld16,$Fld17,$Fld18,$Fld19,$Fld20,$Fl +d21,$Fld22,$Fld23, $Fld24,$Fld25,$Fld26,$Fld27,$Fld28,$Fld29,$Fld30,$Fld31,$Fld32,$Fld33, +$Fld34,$Fld35,$Fld36,$Fld37,$Fld38,$Fld39,$Fld40,$Fld41,$Fld42,$Fld43 +,$Fld44,$Fld45,$Fl d46,$Fld47,$Fld48,$Fld49,$Fld50,$Fld51,$Fld52,$Fld53,$Fld54,$Fld55,$Fl +d56,$Fld57,$Fld58,$Fld59,$Fld60,$Fld61,$Fld62,$Fld63,$Fld64,$Fld65,$F +ld66,$Fld67) = split(/[|\n]/, $_, 9999); if (!($Fld1 eq '800' || $Fld1 eq '801')) { $CNT{substr($Fld67, 3, 5), $Fld1, $Fld15}++; $COST{substr($Fld67, 3, 5), $Fld1, $Fld15} += $Fld14; } } foreach $l_strSwitch (keys %CNT) { @l_strParams = split($;, $l_strSwitch, 9999); printf "\n%s|%s|%s|%d", $l_strParams[1], $l_strParams[2], $l_strParam +s[3], $CNT{$l_strSwitch}; }
There is a pipe separated file from which certain fields are to be extracted and based on the occurence of a particular type of field, the count has to be gathered. I have cleaned up the initial part of the code where the lines are splitted and the values extracted. Currently I am unable to figure out the implementation of the 3 dimensional hash as in :
$CNT{substr($Fld67, 3, 5), $Fld1, $Fld15}++; $COST{substr($Fld67, 3, 5), $Fld1, $Fld15} += $Fld14;
It would be very helpful to me if someone could explain in simple terms, how is this auto-increment and the addition getting done. The foreach loop gets the values from the %CNT, but I also need the corresponding %COST value in the same line.

Although I am able to get the values, any help in understanding the hash mechanism implemented here, would be very helpful.


Thanks & regards,
Subhankar

Comment on Multidimensional Hash implementation/usage
Select or Download Code
Re: Multidimensional Hash implementation/usage
by moritz (Cardinal) on Sep 17, 2007 at 06:32 UTC
    There are two things you can do to emulate a multi dimensional hash. The first is to use nested hashes:

    my $idx = substr $Fld57, 3, 5; $CNT{$idx}{$Fld1}{$Fld15}++; $COST{$idx}{$Fld1}{$Fld15} += $Fld14;

    The second possibility is to use a separator to join the indexes. Be sure that the separator doesn't occur in the indexes:

    my $idx = substr $Fld57, 3, 5; $CNT{$idx . $Fld1 . $Fld15}++; $COST{$idx . $Fld1 . $Fld15} += $Fld14;

    (. is string concatenation).

    Depending on how you want to retrieve your data, one or the other version might be more suitable for you.

    The usual hints apply: always start your programs with

    use strict; use warnings;

    and declare your variables with my.

      Hello Moritz,

      Thank you for your time on this. The code snippet is the original translation of the AWK script. I posted that as the actual one has a lot of extra code functionality included and I have been using "my", "strict", "warnings" as mentioned in the Llama book from the first line :-)

      I am actually having trouble getting a visual representation of the 3 dimensional hash here. I guess I should have been reading more on data structures :-(

      $CNT{$idx}{$Fld1}{$Fld15}++;

      Is it that, in %CNT the first key ($idx) has the value of another hash that has the key $Fld1 and that again refers to another hash with key $Fld15 - which has its value incremented?
      Please let me know if you need any further information on these and I can email you the full code along with necessary files if required.
      Thanks again for your help :-)
      Subhankar
        %CNT contains indeed another hash for each key, which in turn will contain another hash which in turn contains the "real" data.

        If you want to visualize your data structures, use Data::Dumper:

        use Data::Dumper; ... print Dumper \%CNT;
        The code snippet is the original translation of the AWK script.

        That probably explains where this line came from:

        $[ = 1; # set array base to 1
        If you have a lot of other stuff to add to your perl script, you almost certainly want to make sure to DELETE THAT LINE.

        (If you have already written the additional code, and have made all the adjustments needed to accommodate the non-standard value for $[, that's unfortunate. Still, you should consider deleting that line anyway, and adjusting everything back to "normal".)

        I had never seen or used "a2p" before (I never did a lot of awk scripting). Now that I've seen what it does If the OP code is really an example of what it does, I think I'll avoid it.

      The second possibility is to use a separator to join the indexes. Be sure that the separator doesn't occur in the indexes:
      my $idx = substr $Fld57, 3, 5; $CNT{$idx . $Fld1 . $Fld15}++; $COST{$idx . $Fld1 . $Fld15} += $Fld14;

      Actually, Perl offers some syntactic sugar just for that:

      $foo{$a, $b, $c} is equivalent to $foo{join($;, $a, $b, $c)}

      It is documented in perlvar.

Re: Multidimensional Hash implementation/usage
by jwkrahn (Monsignor) on Sep 17, 2007 at 08:39 UTC

    Based on the code you provided a more perlish way to do what you want is:

    #!/usr/perl5/5.6.1/bin/perl my %data; while ( <> ) { chomp; my ( $Fld1, $Fld14, $Fld15, $Fld67 ) = ( split /\|/, $_, -1 )[ 0, +13, 14, 66 ]; if ( $Fld1 != 800 && $Fld1 != 801 ) { my $key = join '|', substr( $Fld67, 2, 5 ), $Fld1, $Fld15; $data{ $key }{ count }++; $data{ $key }{ cost } += $Fld14; } } for my $l_strSwitch ( keys %data ) { print "\n$l_strSwitch|$data{$l_strSwitch}{count}"; }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://639345]
Approved by Sidhekin
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2014-08-29 05:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (275 votes), past polls