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

while going over the first perl code example from "Programming perl" and in attempt to run it w/ strict, I made couple modification.
Strangely, it's complaining that it doesn't see the data that I have provided at the end of the __END__
I have used this before on other program.. but here seem to be an issue
Can someone point out for me what I am doing wrong?
Also, what is the point of doing
$grades{$student} .= $grade . " ";
I think I understand the .= but not sure of the implication in this.. shouldn't it be just  $grades{$student} = $grade ??
#!/usr/bin/perl -w use strict; my %grades; while (<DAT>) { chomp; my($student,$grade) = split (" ",$_); #$grades{$student} .= $grade . " "; $grades{$student} = $grade; } for (sort keys %grades) { my $scores = 0; my $total = 0; my @grades = split(" ", $grades{$_}); for (@grades) { $total += $_; $scores++; } my $average = $total / $scores; print "$_: $grades{$_}\tAverage: $average\n"; } __END__ lee 99 lee 100 kim 90 kim 90 kim 95 kim 100 kim 50 lee 75 :!perl -c ./././perl.score Name "main::DAT" used only once: possible typo at ./././perl.score lin +e 7. ./././perl.score syntax OK

Replies are listed 'Best First'.
Re: first perl example from perl book
by chromatic (Archbishop) on Jan 15, 2008 at 06:25 UTC

    DAT should be DATA.

    As for your second question, the quoted line appends a space character before appending to the hash value. Your rewrite leaves out the space character. This may be significant.

      thank you!!
      #!/usr/bin/perl -w use strict; my %grades; while (<DATA>) { chomp; my($student,$grade) = split (" ",$_); $grades{$student} .= $grade . " "; #$grades{$student} = $grade; print "\$grades{$student} is $grades{$student}\n"; } for (sort keys %grades) { my $scores = 0; my $total = 0; my @grades = split(" ", $grades{$_}); for (@grades) { $total += $_; $scores++; } my $average = $total / $scores; print "$_: $grades{$_}\tAverage: $average\n"; } __END__ lee 90 lee 100 kim 90 kim 90 ./././perl.score $grades{lee} is 90 $grades{lee} is 90 100 $grades{kim} is 90 $grades{kim} is 90 90 kim: 90 90 Average: 90 lee: 90 100 Average: 95 so $grades{$student} .= $grade . " "; is more like $grades
      I also tried this for just education.(which btw is not the same solution and answer).
      #!/usr/bin/perl -w use strict; use diagnostics; my %grades; my %student_n; while (<DATA>) { chomp; my($student,$grade) = split (" ",$_); $grades{$student} += $grade; $student_n{$student}++; } for (sort keys %grades) { my $avg = $grades{$_} / $student_n{$_}; print "$_ average of $student_n{$_} exams are $avg\n"; } __END__ lee 90 lee 100 kim 90 kim 90 ~ ./././././perl.score_copy kim average of 2 exams are 90 lee average of 2 exams are 95
        so
        $grades{$student} .= $grade . " "; is more like

        $grades


        No. It is this:
        $grades{$student} = "$grades{$student}$grade ";

        The value of $grade, followed by a space (" "), is appended to any existing value of $grades{$student}. The . operator does texual concatination, whereas += is numeric, and will add the right-hand-side to the left. For example:
        $x = 3; $y = 4; $x .= $y; # gives 34 $x += $y; # gives 7

        No. It's more like

        $grades{$student} = $grades{$student} . $grade . " ";
Re: first perl example from perl book
by dwm042 (Priest) on Jan 15, 2008 at 15:30 UTC
    This is a problem more easily seen than described. If you use conveninetstore's "read" modification (and changing DAT to DATA), you get this result:
    C:\Code>perl averages.pl kim: 50 Average: 50 lee: 75 Average: 75
    If you then revert to the original ".=" code, you get this result:
    C:\Code>perl averages.pl kim: 90 90 95 100 50 Average: 85 lee: 99 100 75 Average: 91.3333333333333
    Clearly, when you do a concatenation, you add data repeatedly to the hash. When you just assign, you get only the last data entry read.
      thank you guys, I see the difference now
      $grades{$student} .= $grade . " "; ./perl.score $grades{lee} is 90 $grades{lee} is 90 100 $grades{kim} is 90 $grades{kim} is 90 90 kim: 90 90 Average: 90 lee: 90 100 Average: 95 $grades{$student} .= " " . $grade ; [root@myserver chaos]# ./perl.score $grades{lee} is 90 $grades{lee} is 90 100 $grades{kim} is 90 $grades{kim} is 90 90 kim: 90 90 Average: 90 lee: 90 100 Average: 95