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

Hi All, I am new to Perl Hashes. could you please help me on this? I have data like below: Input: <INPUT>
Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.00 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00
</INPUT> <OUTPUT> : Expected
Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 44.32 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.59
</OUTPUT> My code:
$fulllookupKey = $field[19].' '. $field[20].' '. $field[17].' + '.$field[10].' '.$field[23]; if (exists($output{$fulllookupKey})) { $output{$fulllookupKey}->[0] += $field[4]; $output{$fulllookupKey}->[1] += $field[21]; } else { $output{$fulllookupKey}->[0] = $field[4]; $output{$fulllookupKey}->[1] = $field[21]; } } for my $key (sort keys %output) { my $Summry = substr($key,0,7); my $Summary; if ($load_data{$Summary}) { $Summary; = $load_data{$Summary}; } my $Summry1 = substr($key,8,7); my $Detial_Summary; my $Source = substr($key,16,100); if ($load_data1{$Detial_Summary}) { $Detial_Summary = $load_data1{$Detial_Summary}; } print Out $Summary;." \t" . " \t" . " \t". "\t" ."\t" +."\t" ."\n"; print Out " \t" . $Detial_Summary." \t" . " \t" . " \t". "\t" +."\t" ."\t" . "\t" ."\n"; print Out " \t" . " \t" . $Source."\t".sprintf("%.2f", $output +{$key}->[0])."\t".sprintf("%.2f", $output{$key}->[1])."\n"; }
<OUTPUT>: (what i got)
Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.32 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00
</OUTPUT>

Replies are listed 'Best First'.
Re: Perl Hash
by NetWallah (Canon) on Apr 17, 2013 at 04:31 UTC
    Here is one way to do it:
    use strict; use warnings; my %h; while (<DATA>){ chomp; next if length($_) < 30; my ($k1, $k2,$k3, $val) = unpack("A8 x1 A15 x1 A33 x1 A5", $_); $h{$k1}{$k2}{$k3} += $val; } for my $k1 (sort keys %h){ print "$k1\n"; for my $k2 ( sort keys %{ $h{$k1} } ) { print "\t$k2\n"; for my $k3 ( sort keys %{ $h{$k1}{$k2} } ) { print "\t\t$k3 $h{$k1}{$k2}{$k3}\n"; } } } __DATA__ Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.00 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00
    prints:
    Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 44.32 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 44.59

                 "I'm fairly sure if they took porn off the Internet, there'd only be one website left, and it'd be called 'Bring Back the Porn!'"
            -- Dr. Cox, Scrubs

      Hi, Thanks a lot for the inputs. how can i ge this ouput for the same code. <DATA> Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 44.32 EMC CHECK Grand_Total 1 44.32 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 44.59 EMC CHECK1 Grand_Total 1 44.59 </DATA>
        Use <code> tags, not <DATA>.

        To get the grand totals, add the following as the last line inside the WHILE loop:

        $h{$k1}{$k2}{+substr($k3,0,10) . " Grand Total"} += $val;
        This is a kludgy way to do it, but, given your sparse data definition, it does put out a grand total.

        A more robust implementation would require one more level of hashing - I leave that as an exercise for you to implement.

                     "I'm fairly sure if they took porn off the Internet, there'd only be one website left, and it'd be called 'Bring Back the Porn!'"
                -- Dr. Cox, Scrubs

Re: Perl Hash
by CountOrlok (Friar) on Apr 17, 2013 at 04:25 UTC
    Where to begin...

    First, it would make it easier to figure out what is going on if you could reformat the input/output (put them in code tags).

    I got several issues with this code but I think the main issue you is that you have a variable named $Summry and one called $Summary which is undefined. Then you have $Detial_Summary which is also undefined

    BTW, the first if-else clause is unnecessary because of auto-vivification.

    I would rather combine (i.e. join) the fields on an uncommon character like '^' or '|' instead of spaces. It later makes it easier to split the fields back rather than using substr.

      My code:
      $fulllookupKey = Summary."\t".Detial_Summary."\t".Name."\t".Location." +\t".Sub_Location."\t". <code> if (exists($output{$fulllookupKey})){ $output{$fulllookupKey}->[0] += $Count; $output{$fulllookupKey}->[1] += $Amount; } else { $output{$fulllookupKey}->[0] = $Count; $output{$fulllookupKey}->[1] = $Amount; } for my $key (sort keys %output){ my $Summary = substr($key,0,7); my $Detial_Summary = substr($key,8,7); my $Source = substr($key,16,100); print Out $Summary;." \t" . " \t" . " \t". "\t" ."\t" ."\t" ."\n"; print Out " \t" . $Detial_Summary." \t" . " \t" . " \t". "\t" ."\t" ." +\t" . "\t" ."\n"; print Out " \t" . " \t" . $Source."\t".sprintf("%.2f", $output{$key}-> +[0])."\t".sprintf("%.2f", $output{$key}->[1])."\n"; }
      <INPUT> Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.32 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00 <INPUT> <OUTPUT>: (what i got) Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.32 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00 </OUTPUT> Expected Output: <OUTPUT> Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 44.32 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.59 </OUTPUT>

        Put everything which is code/data inside code tags

Hashes of Hash in perl
by Rajsai2825 (Novice) on Apr 17, 2013 at 09:39 UTC
    Hi, could you please help on this? MY Code:
    $fulllookupKey = $field[1]."\t". $field[2]."\t". $field[3]."\ +t".$field[4]."\t".$field[5]; $RescatKey = $field[1]; $RessubcatKey = $field[2]; $MasterSrkey = $field[3]; $field[4] =~ s/^\s+//; $field[21] =~ s/^\s+//; $Count = $field[6]; $Amount = $field[7]; if (exists($output{$RescatKey}{$RessubcatKey}{$fulllookupKey})) + { $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[0] += $fie +ld[6]; $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[1] += $fie +ld[7]; } else { $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[0] = $fiel +d[6]; $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[1] = $fiel +d[7]; } } for my $k1 (sort keys %output){ print "$k1\n"; for my $k2 ( sort keys %{ $output{$k1} } ) { print "\t$k2\n"; for my $k3 ( sort keys %{ $output{$k1}{$k2} } ) { my $Source = substr($k3,16,100); my $Source1 = substr($k3,16,07); print "\t\t$Source $output{$k1}{$k2}{$k3}->[0]\t$output{$k1}{$ +k2}{$k3}->[1]\n"; print "\t\t$Source1\t TOTAL \t$output{$k1}{$k2}{$k3}->[1]\t$outpu +t{$k1}{$k2}{$k3}->[0]\n"; } } }
    INPUT is:
    <code> Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.00 Summary Detial_Summary EMC CHECK KBCDEFGHI AZ_checker 1 10.00 Summary Detial_Summary EMC CHECK KBCDEFGHI AZ_checker 1 14.00 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00 Summary1 Detial_Summary1 EMC CHECK1 HGIJHKKIF AZ_checker 1 10.00 Summary1 Detial_Summary1 EMC CHECK1 HGIJHKKIF AZ_checker 1 14.00
    </code> OUTPUT expected is:
    Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 2 44.32 EMC CHECK KBCDEFGHI AZ_checker 2 24.00 EMC CHECK TOTAL 4 64.32 EMC CHECK1 abcdefghi AZ_checker 2 44.59 EMC CHECK1 HGIJHKKIF AZ_checker 2 24.00 EMC CHECK1 TOTAL 4 68.59 Detial_Summary TOTAL 8 132.91 Summary TOTAL 8 132.91

      How about this? Still lots of open questions...

      I have ignored the first 3 columns as they do not seem to make any difference (even though they have different entries, these differences are ignored in your desired output). In order to check whether columns line up properly, open in Excel with TAB delimited.

      use strict; use warnings; my %output; my %total; while (my $line = <DATA>){ chomp $line; my @field = split /\s+/, $line; # fields 0, 1, 2 do seem to be required $output{$field[3]}{$field[4]}{$field[5]}{COUNT} += $field[6]; $output{$field[3]}{$field[4]}{$field[5]}{VALUE} += $field[7]; $total{$field[3]}{COUNT} += $field[6]; $total{$field[3]}{VALUE} += $field[7]; $total{TOTAL}{COUNT} += $field[6]; $total{TOTAL}{VALUE} += $field[7]; } print "Summary\n"; print "\tDetailed Summary\n"; for my $k1 (sort keys %output){ for my $k2 ( sort keys %{ $output{$k1} } ) { for my $k3 ( sort keys %{ $output{$k1}{$k2} } ) { print "\t\tEMC\t$k1\t$k2\t$k3\t$output{$k1}{$k +2}{$k3}{COUNT}\t$output{$k1}{$k2}{$k3}{VALUE}\n"; } } print "\t\tEMC\t$k1\tTOTAL\t\t$total{$k1}{COUNT}\t$total{$k1}{ +VALUE}\n"; } print "\tDetailed Summary\tTOTAL\t\t$total{TOTAL}{COUNT}\t$total{TOTAL +}{VALUE}\n"; print "Summary\n"; __DATA__ Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.00 Summary Detial_Summary EMC CHECK KBCDEFGHI AZ_checker 1 10.00 Summary Detial_Summary EMC CHECK KBCDEFGHI AZ_checker 1 14.00 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00 Summary1 Detial_Summary1 EMC CHECK1 HGIJHKKIF AZ_checker 1 10.00 Summary1 Detial_Summary1 EMC CHECK1 HGIJHKKIF AZ_checker 1 14.00

      Is this post a continuation of this thread Perl Hash ?

        Yes
      Just one friendly piece of advice: Please stick to one convention when using variable names. You have some variables with like $Summary (a convention no one uses), some like $fulllookupKey (which should really have been $fullLookupKey) and I also saw something like $load_data in one of your post.

      Sticking to one convention helps you more than anyone else. You don't need to keep going back to check how you spelled that variable.

      Hi Rajsai2825,
      I know you have been given a workable script, but I just want to point out that you can do all your "stuff" using just a hash and function unpack.
      As shown below. (ofcourse, I wouldn't drop all the "jar of honey" on your laps!:))

      use warnings; use strict; my %input; my $total; my $grand_total; while (<DATA>) { chomp; next if /^$/; my ( $k1, $k2, $k3, $k4, $k5 ) = unpack("x25 A10 A10 x1 A10 x1 A1 +x1 A5"); $total += $k4; $grand_total += $k5; push @{ $input{'summary'}{'Detial_Summary'}{$k1}{$k2}{$k3}{ ++$k4 +} }, $k5; } push @{ $input{'summary'}{'TOTAL'}{$total} }, $grand_total; use Data::Dump; dd \%input; __DATA__ Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 20.32 Summary Detial_Summary EMC CHECK abcdefghi AZ_checker 1 24.00 Summary Detial_Summary EMC CHECK KBCDEFGHI AZ_checker 1 10.00 Summary Detial_Summary EMC CHECK KBCDEFGHI AZ_checker 1 14.00 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 20.59 Summary1 Detial_Summary1 EMC CHECK1 abcdefghi AZ_checker 1 24.00 Summary1 Detial_Summary1 EMC CHECK1 HGIJHKKIF AZ_checker 1 10.00 Summary1 Detial_Summary1 EMC CHECK1 HGIJHKKIF AZ_checker 1 14.00

      OUTPUT
      { summary => { Detial_Summary => { "EMC CHECK" => { " abcdefghi" => { AZ_checker => { 2 => [20.32, + "24.00"] } }, " KBCDEFGHI" => { AZ_checker => { 2 => ["10.00 +", "14.00"] } }, }, "EMC CHECK1" => { " abcdefghi" => { AZ_checker => { 2 => [20.59, + "24.00"] } }, " HGIJHKKIF" => { AZ_checker => { 2 => ["10.00 +", "14.00"] } }, }, }, TOTAL => { 8 => [136.91] }, }, }
      If you tell me, I'll forget.
      If you show me, I'll remember.
      if you involve me, I'll understand.
      --- Author unknown to me
      Your code is incomplete, it doesn't read input
        Please find the subroutine:
        while (chomp(@field = split (/\t/, <FILE>))) { next unless ($field[0] =~ /^$USG_REC_IND/); foreach my $key ( keys %load_data ) { { if (length($key) == 0) { next; } } } $fulllookupKey = $field[1]."\t". $field[2]."\t". $field[3]."\t".$ +field[4]."\t".$field[5]; $RescatKey = $field[1]; $RessubcatKey = $field[2]; $MasterSrkey = $field[3]; $field[4] =~ s/^\s+//; $field[21] =~ s/^\s+//; $Count = $field[6]; $Amount = $field[7]; if (exists($output{$RescatKey}{$RessubcatKey}{$fulllookupKey})) { $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[0] += $fie +ld[6]; $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[1] += $fie +ld[7]; } else { $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[0] = $fiel +d[6]; $output{$RescatKey}{$RessubcatKey}{$fulllookupKey}->[1] = $fiel +d[7]; } } for my $k1 (sort keys %output){ print "$k1\n"; for my $k2 ( sort keys %{ $output{$k1} } ) { print "\t$k2\n"; for my $k3 ( sort keys %{ $output{$k1}{$k2} } ) { my $Source = substr($k3,16,100); print "\t\t$Source $output{$k1}{$k2}{$k3}->[0]\t$output{$k1}{$k2} +{$k3}->[1]\n"; print "\t\t$Source1\t TOTAL \t$output{$k1}{$k2}{$k3}->[1]\t$outpu +t{$k1}{$k2}{$k3}->[0]\n"; } } } close (OUT); }