LPM: "on break" processing in perl?

Steve Lane sml at zfx.com
Tue Jan 23 09:26:05 CST 2001


a hash of hashes of lists is what you want here, with one step
for stuffing the hash with data and another step to print the
data.  the HoHoL will be:

hash (with coursenumber as key) of 
  hashes (with sectionnumber as key) of 
    lists (of ssnums)

my code (tested) is below.  note that the syntax of deferencing
multidim data structures looks hairy to almost everyone until
they get used to it.  but getting used to it is a vital thing
to do if you want to use Perl.

#!/usr/bin/perl

# data structure:
# hash (coursenumber as key) 
#   of hashes (sectionnumber as key) 
#     of lists (of ssnums)

my %data;  # overall data structure.  another name would be better.

# stuff data into %data
while (<DATA>) {
  chomp;
  my($course, $section, $ss) = split /,\s+/;
  push @{ $data{$course}{$section} }, $ss;
}

# print data
for my $course (sort keys %data) {
  my %sections = %{ $data{$course} };  # save typing
  my $num_students = sum( map scalar @{ $sections{$_} }, 
                          keys %sections );
  print "$course: $num_students students\n";
  for my $section (sort { $a <=> $b } keys %sections) {
    my @ss = @{ $sections{$section} };
    my $num_students = @ss;
    print "\tSection $section: $num_students students\n";
    for my $ss (sort @ss) {
      print "\t\t$ss\n";
    }
  }
}

sub sum { my $sum; $sum += $_ for @_; $sum }

__DATA__
CS101, 1, 000-00-1111
CS101, 1, 000-00-2222
CS101, 1, 000-00-3333
CS101, 2, 000-00-4444
CS101, 2, 000-00-5555
CS117, 1, 000-00-1111
CS117, 1, 000-00-9999

__END__

David Hempy wrote:
> 
> I keep running into the situation where I am reading rows from a database,
> presenting the rows in groups and subgroups.  For example:
> 
> select coursenumber, sectionnumber, ssnum
>         from studentview
> 
> This might return:
> 
> CS101, 1, 000-00-1111
> CS101, 1, 000-00-2222
> CS101, 1, 000-00-3333
> CS101, 2, 000-00-4444
> CS101, 2, 000-00-5555
> CS117, 1, 000-00-1111
> CS117, 1, 000-00-9999
> 
> I would like to display something like:
> 
> CS101: 7 students
>         Section 1: 3 students
>                 000-00-1111
>                 000-00-2222
>                 000-00-3333
>         Section 2: 2 students
>                 000-00-4444
>                 000-00-5555
> CS117: 2 students
>         Section 1: 2 students
>                 000-00-1111
>                 000-00-9999
> 
> (Actually, I am usually plugging these into HTML tables, but the idea is
> the same.)
> 
> I would like to do something like:
> 
> while fetch {
>         on break in $coursenumber
>                 print count($coursenumber);
>         on break in $sectionnumber
>                 print "\t" . count($sectionnumber);
> 
>         print "\t\t $ssnum";
> }
> 
> It's not so hard to generate the breaks by setting $last_sectionnumber each
> time after comparing the current $sectionnumber to the
> $last_sectionnumber.  That would suffice if I just wanted a <hr> or similar
> between each group.  It becomes more problematic when I want to
> telepathically print the subtotals before I've stepped through the data.
> 
> I've gotten around this in the past by building up little chunks of the
> output in different scalars, then outputting all the little pieces in the
> right order when the group changes.  I then have to repeat this break
> processing again after the loop exits, assuming that any were found at
> all.  Ugh.  Double that for two-level grouping.  Double ugh.
> 
> I have in some programs saved the break lines with "~SUBTOTAL~" in it, then
> do a s/~SUBTOTAL~/$subtotal/ later.  Effective, but embarassing.
> 
> Anyone have any tips or methods to share?  I have a suspicion I should
> separate analysis and presentation into two passes, with some combination
> of arrays/hashes between the two.  I think I'll cipher on that for a while...
> 
> -dave
> 
> --
> David Hempy
> Internet Database Administrator
> Kentucky Educational Television
> <hempy at ket.org> -- (859)258-7164 -- (800)333-9764

--
Steve Lane <sml at zfx.com>



More information about the Lexington-pm mailing list