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

I'm barely an intermediate perl programmer so please bear with me. I know what the problem is, I just don't know the syntax to fix it.

I have one script (not listed here) which writes entries to a datafile. The code below is a portion of the script that outputs that same data as a table into a template. On this output page, I want to group entries by neighborhood. Currently, every entry creates a new neighborhood group (not grouping entries with the same neighborhood together. Repeating the same neigborhood) and under each grouping lists every entry regardless of its neighborhood (Repeating information). Hmm... This may sound confusing... You can see the output in action here:

http://www.jyadvertising.com/cgi-bin/homesreadynow_index.cgi

And this is an example of how I am trying to output the page:

http://www.jyadvertising.com/cristohomes/example.html

open (FILE, "$datafile") || &fatal_error("Unable to open $datafile"); &lock(FILE); @messages = <FILE>; &unlock(FILE); close(FILE); for ($a = 0; $a < @messages; $a++) { ($mnum[$a],$maddress[$a],$mimage[$a],$mneighborhood[$a],$mmodelname[$a +],$mmodelelevation[$a],$mbedrooms[$a],$mbathrooms[$a],$mtypeoffoundat +ion[$a],$mschooldistrict[$a],$mprice[$a],$mpaymentsfrom[$a],$mreadyda +te[$a],$mphonenumber[$a],$memail[$a],$chop) = split(/``/,$messages[$a +]); } open (FILE, "$template") || &fatal_error("Unable to open $template"); &lock(FILE); @template = <FILE>; &unlock(FILE); close(FILE); for ($a = 0; $a < @template; $a++) { $_ = $template[$a]; if (/<!--messages-->/) { print "<table width=400 border=0 cellpadding=3 cellspacing=3>\ +n"; print "<tr class=\"typewhite\" bgcolor=\"#000000\">\n"; print "<td><b>Address</b></td>\n"; print "<td><b>Model Name</b></td>\n"; print "<td><b>Price</b></td>\n"; print "<td><b>Availability</b></td>\n"; print "</tr>\n"; foreach $mneighborhood (@mneighborhood) { print "<tr class=\"type\" bgcolor=\"#EEEFDD\"><td colspan= +4><a href=\"../cristohomes/hoods/$mneighborhood.shtml\" class=\"type\ +"><b>$mneighborhood</b></a></td</tr>"; for ($b = 0; $b < @messages; $b++) { print "<tr class=\"type\">\n"; print "<td><a href=\"$indexcgi$queryswitch"; print "action=display\&num=$mnum[$b]\" class=\"red\">$ +maddress[$b]</a></td>\n"; print "<td><a href=\"../cristohomes/homes/$mmodelname[ +$b].shtml\" class=\"red\">\"The $mmodelname[$b]\"</a></td>\n"; print "<td>$mprice[$b]</td>\n"; print "<td>$mreadydate[$b]</td>\n"; print "</tr>\n"; } } print "</table>\n"; } }
I need your wisdom!

update (broquaint): added formatting

Replies are listed 'Best First'.
Re: Help? - Trouble outputting data corectly
by jdporter (Paladin) on Dec 16, 2002 at 22:39 UTC
    In my revision of your code, below, the essential change is that each data record read in is stored as a hash, and each of these hashes is put on a list (actually, in an array). This is much cleaner (and much less error prone) than having a separate array for each input field.

    In order to support your purpose, I've taken it one step further, and made a separate array of records for each neighborhood. There is one top-level data structure, the hash %m. Its keys are the values for the neighborhood field from each of the lines read in. The corresponding values are arrays of records, where each record is a hash, as explained above.

    And lastly, one other change, which I think makes the code much neater, and also somewhat more efficient: each line of input from the files is processed as it is read in, rather than slurping them up into an array and then stepping over the array.

    Oh -- and I made it use here docs instead of multiple print statements.
    my @fields = qw( num address image neighborhood modelname modelelevation bedrooms +bathrooms typeoffoundation schooldistrict price paymentsfrom readydate phon +enumber email ); my %m; # key: neighborhood name. value: array of records. { open FILE, "< $datafile" or &fatal_error("Unable to open $data +file"); &lock(FILE); while ( <FILE> ) { chomp; my %rec; @rec{@fields} = split /``/; # put each record into the list for that neighborhood: push @{ $m{ $rec{'neighborhood'} } }, \%rec; } &unlock(FILE); close FILE; } open FILE, "< $template" or &fatal_error("Unable to open $template +"); &lock(FILE); while (<FILE>) { open FILE, "< $template" or &fatal_error("Unable to open $template +"); &lock(FILE); while (<FILE>) { if (/<!--messages-->/) { print <<EOF; <table width=400 border=0 cellpadding=3 cellspacing=3> <tr class="typewhite" bgcolor="#000000"> <td><b>Address</b></td> <td><b>Model Name</b></td> <td><b>Price</b></td> <td><b>Availability</b></td> </tr> EOF foreach $neighborhood ( sort keys %m ) { print <<EOF; <tr class="type" bgcolor="#EEEFDD"> <td colspan=4> <a href="../cristohomes/hoods/$neighborhood.shtml" cla +ss="type"> <b>$neighborhood</b> </a> </td> </tr> EOF for my $rec ( @{ $m{ $neighborhood } } ) { print <<EOF; <tr class="type"> <td> <a href="$indexcgi${queryswitch}action=display&num=$r- +>{'num'}" class="red"> $r->{'address'} </a> </td> <td> <a href="../cristohomes/homes/$r->{'modelname'}.shtml" + class="red"> "The $r->{'modelname'}" </a> </td> <td>$r->{'price'}</td> <td>$r->{'readydate'}</td> </tr> EOF } } print "</table>\n"; } } &unlock(FILE); close FILE;

    jdporter
    ...porque es dificil estar guapo y blanco.

      Thank you so very much! All of my problems have been solved!
Re: Help? - Trouble outputting data corectly
by John M. Dlugosz (Monsignor) on Dec 16, 2002 at 21:58 UTC
    Quick fix: inside the for-each-message loop, reject those that should not be in this section:
    next unless $mneighborhood[$b] eq $mneighborhood;
    put this at the top of the for loop, before printing anything. It will skip it if the current message's neighborhood is not equal to the value in the outer foreach loop's.

    A better approach would be to store things in a list of records rather than in paralell arrays. Then you can grep-out by any criteria you want.

    —John