Contents
10. Data-Processing: Grade Book Example
This example produces a score summary report by combining data from a simple
file of student info and a file of their scores.
Input file "stufile" is delimited with colons. Fields are Student
ID, Name, Year:
123456:Washington,George:SR
246802:Lincoln,Abraham "Abe":SO
357913:Jefferson,Thomas:JR
212121:Roosevelt,Theodore "Teddy":SO
Input file "scorefile" is delimited with blanks. Fields are Student
ID, Exam number, Score on exam. Note that Abe is missing exam 2:
123456 1 98
212121 1 86
246802 1 89
357913 1 90
123456 2 96
212121 2 88
357913 2 92
123456 3 97
212121 3 96
246802 3 95
357913 3 94
The desired report:
Stu-ID Name... 1 2 3 Totals:
357913 Jefferson,Thomas 90 92 94 276
246802 Lincoln,Abraham "Abe" 89 95 184
212121 Roosevelt,Theodore "Teddy" 86 88 96 270
123456 Washington,George 98 96 97 291
Totals: 363 276 382
The program that made this report:
#!/usr/local/bin/perl
# Gradebook - demonstrates I/O, associative
# arrays, sorting, and report formatting.
# This accommodates any number of exams and students
# and missing data. Input files are:
$stufile='stufile';
$scorefile='scorefile';
# If file opens successfully, this evaluates as "true", and Perl
# does not evaluate rest of the "or" "||"
open (NAMES,"<$stufile")
|| die "Can't open $stufile $!";
open (SCORES,"<$scorefile")
|| die "Can't open $scorefile $!";
# Build an associative array of student info
# keyed by student number
while (<NAMES>) {
($stuid,$name,$year) = split(':',$_);
$name{$stuid}=$name;
if (length($name)>$maxnamelength) {
$maxnamelength=length($name);
}
}
close NAMES;
# Build a table from the test scores:
while (<SCORES>) {
($stuid,$examno,$score) = split;
$score{$stuid,$examno} = $score;
if ($examno > $maxexamno) {
$maxexamno = $examno;
}
}
close SCORES;
# Print the report from accumulated data!
printf "%6s %-${maxnamelength}s ",
'Stu-ID','Name...';
foreach $examno (1..$maxexamno) {
printf "%4d",$examno;
}
printf "%10s\n\n",'Totals:';
# Subroutine "byname" is used to sort the %name array.
# The "sort" function gives variables $a and $b to
# subroutines it calls.
# "x cmp y" function returns -1 if x<y, 0 if x=y,
# +1 if x>y. See the Perl documentation for details.
sub byname { $name{$a} cmp $name{$b} }
# Order student IDs so the names appear alphabetically:
foreach $stuid ( sort byname keys(%name) ) {
# Print scores for a student, and a total:
printf "%6d %-${maxnamelength}s ",
$stuid,$name{$stuid};
$total = 0;
foreach $examno (1..$maxexamno) {
printf "%4s",$score{$stuid,$examno};
$total += $score{$stuid,$examno};
$examtot{$examno} += $score{$stuid,$examno};
}
printf "%10d\n",$total;
}
printf "\n%6s %${maxnamelength}s ",'',"Totals: ";
foreach $examno (1..$maxexamno) {
printf "%4d",$examtot{$examno};
}
print "\n";
exit(0);
Perl allows an associative array to be "tied" to a genuine database, such
that expressions like $record = $student{$key} use the database. See the "dbm"
and "tie" functions.