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

The code is reading in several files one at a time and either creating a key value pair or amending the value for the key if it exists. The trouble is keys with single values only print out the key. I understand that the value needs to be associated if the key doesn't exist but my attempts have not worked. Can you please point out my blunder?
while(<RPT>) { chop; if ($_ =~ s/^(\D+.*\d{4}\s+)(\D+.*)(\w{11})$/$1 $2 $3/ +) { $msg = $2; fmt_rpt($msg); $key = "$3"; if (exists($analysis{$key})) { $val .= "$msg"; } else { #$val = "$msg"; $analysis{$key} = "$val"; } } else { print "Program Error 2\n"; exit 1; }

20041119 Janitored by Corion: Fixed broken code tag

Replies are listed 'Best First'.
Re: Hash Trouble
by ikegami (Patriarch) on Nov 19, 2004 at 17:17 UTC

    chop should be chomp.

    "$3" should be $3.

    "$msg" should be$msg.

    "$val" should be $val.

    Why are you using a substitution instead of if ($_ =~ /^(\D+.*\d{4}\s+)(\D+.*)(\w{11})$/?

    $_ =~ can be omitted.

    It's bad to use $1, $2, etc after calling a function after they've been set.

    fmt_rpt($msg) should probably be $msg = fmt_rpt($msg).

    And the answer to your question: $val .= "$msg"; should $analysis{$key} .= $msg. I'm not sure if that's exactly what you want, but you never save $val into the hash, so your problem is definitely here.

    $val is used but never set in the else part of the if.

    And the answer to your question: $val .= "$msg"; should $analysis{$key} .= $msg. I'm not sure if that's exactly what you want, but you never save $val into the hash, so your problem is definitely here.

    $1 is never used. I'm going to leave the capture in the code below, in case you plan on using $1.

    Fixed code:

    while(<RPT>) { chomp; if (/^(\D+.*\d{4}\s+)(\D+.*)(\w{11})$/) { $key = $3; $msg = $2; # Maybe should be: $msg = fmt_rpt($msg); fmt_rpt($msg); if (exists($analysis{$key})) { $analysis{$key} .= $msg; } else { $analysis{$key} = $msg; } } else { print "Program Error 2\n"; exit 1; }
      Thank you for all of the information! The new code was missing the association of $val in the else statement so it was added and the new code looks like: $1 = time stamp $2 = error message $3 = unique identifer I am not sure if the time stamp information is going to be used.
      while(<RPT>) { chomp; if (/^(\D+.*\d{4}\s+)(\D+.*)(\w{11})$/) { $key = $3; $msg = $2; fmt_rpt($msg); if (exists($analysis{$key})) { $analysis{$key} .= $msg; } else { $val = $msg; $analysis{$key} = $val; } } else { print "Program Error 2\n"; exit 1; }
      For me I would rather build one hash table instead of multiple hash tables and then merging them. To me it seems like a waste what are your thoughts?
        The new code was missing the association of $val

        Not at all. There's no reason to do
        $val = $msg;
        $analysis{$key} = $val;
        when
        $analysis{$key} = $msg;
        suffices.

        For me I would rather build one hash table instead of multiple hash tables and then merging them. To me it seems like a waste what are your thoughts?

        To which multiple hashes are you refering? You mean if you if you were to keep the timestamp? You could do something like:

        while(<RPT>) { chomp; if (/^(\D+.*\d{4}\s+)(\D+.*)(\w{11})$/) { my $timestamp = $1; my $msg = $2; my $key = $3; fmt_rpt($msg); if (exists($analysis{$key})) { $analysis{$key}[1] .= $msg; } else { $analysis{$key} = [ $timestamp, $msg ]; } } else { print "Program Error 2\n"; exit 1; }

        See perllol for details. This would be a HoA (Hash of Arrays), which is similar to the mentioned AoA (Array of Arrays).