Training, Open Source computer languages

This is page http://www.wellho.net/forum/Perl-Programming/Sorting-Data.html

Our email: info@wellho.net • Phone: 01144 1225 708225

 
For 2023 (and 2024 ...) - we are now fully retired from IT training.
We have made many, many friends over 25 years of teaching about Python, Tcl, Perl, PHP, Lua, Java, C and C++ - and MySQL, Linux and Solaris/SunOS too. Our training notes are now very much out of date, but due to upward compatability most of our examples remain operational and even relevant ad you are welcome to make us if them "as seen" and at your own risk.

Lisa and I (Graham) now live in what was our training centre in Melksham - happy to meet with former delegates here - but do check ahead before coming round. We are far from inactive - rather, enjoying the times that we are retired but still healthy enough in mind and body to be active!

I am also active in many other area and still look after a lot of web sites - you can find an index ((here))
Sorting Data

Posted by dabbler (dabbler), 20 August 2003
Hi.

I think I could do with an explaination of sorting, as I looked at one script's sorting method and it looked like hieroglyphics to me.  

I have a small simple script that reads data from a text file, to maintain a directory of organisations. I'd like to sort this by city, alphabetically, instead of in the order that they are added to the file. I know nothing about sorting at all, any light shed would be great.

Code:
elsif ($form{'action'} eq "view"){

open (USRDAT,"$DATA_DIR/directory.dat");
@dat = <USRDAT>;
close (USRDAT);

print "$HEADER";

print "<table width=\"100%\" cellspacing=1 cellpadding=5 border=0 align=center>\n";
print "<tr><td bgcolor=\"#fffffff\" valign=\"top\" width=\"25%\"><font color=\"#000000\" size=\"2\"><b>City</b></font></td><td bgcolor=\"#fffffff\" valign=\"top\" width=\"25%\"><font color=\"#000000\" size=\"2\"><b>Organization</b></font></td><td bgcolor=\"#fffffff\" valign=\"top\"><font color=\"#000000\" size=\"2\"><b>Details</b></font></td><td bgcolor=\"#ffffff\" valign=\"top\" width=\"12%\"><font color=\"#000000\" size=\"2\"><b>Email</b></font></td></tr>\n";

 foreach $line (@dat) {
     @entry = split(/#!#/,"$line");
     
       print "<tr><td bgcolor=\"#cccccc\" valign=\"top\" class=\"contentHead\">$entry[0]</td><td bgcolor=\"#cccccc\" valign=\"top\" class=\"content\">$entry[1]</td><td bgcolor=\"#cccccc\" valign=\"top\" class=\"content\">$entry[2]</td><td bgcolor=\"#cccccc\" class=\"content\" valign=\"top\">$entry[3]</td></tr>\n";
 }
print "</table><br>\n";

print "$FOOTER";

print "</body>

</html>\n";
exit;
}


I need these sorted by $entry[0], alphabetically.

On another note, what makes the difference in how returns are handled, such as, here on the forum, returns are kept in the formatting, and in my script currently, they are only kept as spaces?

Many thanks in advance.

Posted by admin (Graham Ellis), 20 August 2003
First reaction - replace
           foreach $line (@dat) {
by
           foreach $line (sort @dat) {
which is quick and dirty - it uses Perl's default way of sorting (which has been decribed to me as Asciibetical) and it will be fine for what you want so long as city entries have consistent capitalisation.

It's only that easy because you want to sort in the default way by what happens to be the first field on the line.  If you wanted to sort (say) by the second field on the each line, you would change the foreach statement to
           foreach $line (sort somehow @dat) {
and provide a subroutine called somehow to tell perl how to tell records apart.  In my example:
           sub somehow {
                  @x = split(/#!#/,$a);
                  @y = split(/#!#/,$b);
                   return ($x[1] cmp $y[1]);
                   }
(Ask if you need more explanation! - basically it compares two items which come in in variables $a and $b and returns 0 if they're the same, negative if $b is before $a and positive if $b is after $a)

On the new line subject ....   Your \n-s will be visible as line breaks if you do a view source on the browser; if you want line breaks to appear in the viewed HTML, you need to replace them by <br>.  Basically, browsers treat new lines as white space and need to be told explicitly where to break with <br> or <p>.



Posted by dabbler (dabbler), 20 August 2003
Thank you Graham. I'm relieved I can fall back on that simple default sorting, as the subroutine went a bit over my head. No further expanation needed however, I'll tackle that one another time.

Posted by 007 (007), 5 September 2003
below is a file named furniture.txt.
How can I sort this by bid and then print the lines in order of highest to lowest bids?

#####################################################################
($cat ,$item, $title, $numbid, $bid, $image, $buyit, $reserve)= line

furniture:::1063785605:::chair:::0:::60.00:::0:::100.00:::80.00
furniture:::1064044827:::couch:::0:::57.00:::0:::110.00:::90.00
furniture:::1062889216:::desk:::0:::70.00:::0:::10000.00:::8000.00

This sub sorts the file ,but not by a specific variable.

sub sort{
open FILE, "$config{'basepath'}furniture.txt";
my @lines = <FILE>;
close (FILE);
my @sorted = sort @lines;
print "@sorted<BR>";
}


#####################################################

I have tried this many different ways ,but it's beyond my limited knowledge  

If anyone can help I would really appreaciate it.
TIA



Posted by admin (Graham Ellis), 6 September 2003
Code:
#!/usr/bin/perl

my @lines = <DATA>;
my @sorted = sort bybid @lines;
print @sorted;

sub bybid {
($cat1 ,$item1, $title1, $numbid1, $bid1, $image1, $buyit1, $reserve1)= split(/:::/,$a);
($cat2 ,$item2, $title2, $numbid2, $bid2, $image2, $buyit2, $reserve2)= split(/:::/,$b);
return ($bid2 <=> $bid1);
}


__END__
furniture:::1063785605:::chair:::0:::60.00:::0:::100.00:::80.00
furniture:::1064044827:::couch:::0:::57.00:::0:::110.00:::90.00
furniture:::1062889216:::desk:::0:::70.00:::0:::10000.00:::8000.00


Sorting always "gets" people who are new to Perl .... if you want to sort in a non-default way, you provide the sort function with an extra parameter, not comma separated and before the list to be sorted, which compares two records (passed into it as $a and $b - you can't change these names) and returns a negative, zero or positive number if they're already in the right order, the same as far as the sort is concerned, or need swapping over.

Looking at the example above, we have asked the perogram to sort the list called @lines, using the function bybid to compare pairs of lines - the subroutine name is passed in to Perl's sort routine, which calls back to our code, running our bybid routine as many times as it needs to.  If you were sorting a file with hundreds of records, it would be called thousands of times.  The clever bit of work that perl's sort function is doing is managing which records need to be compared, and the result of those comparisions - you provide the comparator.

The <=> operator used in bybid does a numerical comparison and returns the -ve, 0, +ve response that we want - it's in Perl really just for the purpose of making sorting easier.  There's an operator called cmp that does the same thing for a string comparison.

"side notes", 007 ... Firstly, welcome to the board.   Secondly, you might like to change the name of your sub in the original code from "sort" to something that isn't the same as a system function name - Perl might not have a problem, but it sure as heck may confuse you later when you come to maintain the code and have two things called "sort".

Posted by 007 (007), 6 September 2003
  Thank you for the welcome and the code,Graham.This is just what I was looking for.  I will be using this for my catagory index files in an auction script.
I should be able to use it to sort by any of the variables.I have searched the web for over a week now but this is the first place I have found a solution that worked. Great forum! Keep up the good work.  
  Thanks again,
       Allan

P.S. I will change the name of my sub to something else  
   



This page is a thread posted to the opentalk forum at www.opentalk.org.uk and archived here for reference. To jump to the archive index please follow this link.

© WELL HOUSE CONSULTANTS LTD., 2024: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho