CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
sort and print

 



waherne
Novice

Jan 7, 2001, 3:46 PM

Post #1 of 7 (787 views)
sort and print Can't Post

Hi,

I have a database and want to print selected folders in alphabetical order (by surname or city). The database looks like this:

Folder|First name|Surname|City|Country
0|tom|smith|new york|usa
1|tim|conway|paris|france
2|mary|jones|chelsea|uk
2|tina|butler|dublin|ireland
3|frank|conway|berlin|germany
3|michael|buckley|Cork|Ireland

A user can select a folder number and sortby surname or city option, and then hit a print button.
e.g. selecting folder 2 and sorting by surname would print tina first then mary and nothing else. If city was the selected sort, then mary would be printed first then tina.

Does anyone have a piece of readymade code to do that for me? I have gone through all the past questions on this but am getting very confused. Your help would be greatly appreciated.

Willie





zanardi
journeyman

Jan 7, 2001, 7:14 PM

Post #2 of 7 (781 views)
Re: sort and print [In reply to] Can't Post

Here is a sorting routine:

@sortedarray = sort {lc($a) cmp lc($b)} @array;

My BBS


rGeoffrey
User / Moderator

Jan 7, 2001, 9:21 PM

Post #3 of 7 (777 views)
Re: sort and print [In reply to] Can't Post

In this case we cannot just do a simple sort, or even a simple sort {$a cmp $b} because we need to actually be sorting on things from the middle of the strings.

This is a good time to use my favorite perl function, 'map', not just once, but twice, in a Schwartzian Transform. And because we need to filter the list down to just those that match the folder, we will throw in a grep also.


Code
sub transform_sort { 
my ($folder, $option, @array) = @_;

my %index = (Folder => 0,
'First name' => 1,
Surname => 2,
City => 3,
Country => 4);

return (map { (split ('<->', $_))[1] }
sort
map { join ('<->', lc ((split ('\|', $_))[$index{$option}]), $_) }
grep (/^$folder\|/ , @array)
);
}

Inside the return you must read from bottom to top as each line takes an array as input and passes it on to the command above it.

First grep takes the original @array and only passes on things that begin with $folder. Then the lower map finds the keyword that we want to search on and create an array of 'lc (keyword)<->original string'. Then these strings can pass through the normal boring everyday sort. And lastly we split on '<->' to get the original string back.

If you want to try it youself, here is the rest of my test...


Code
#Folder|First name|Surname|City|Country 
my @array = ('0|tom|smith|new york|usa',
'1|tim|conway|paris|france',
'2|mary|jones|chelsea|uk',
'2|tina|butler|dublin|ireland',
'3|frank|conway|berlin|germany',
'3|michael|buckley|Cork|Ireland');

print ("\nThe original array is:\n ",
join ("\n ", @array),
"\nThe sorted array zanardi version:\n ",
join ("\n ", sort {lc($a) cmp lc($b)} @array),
"\nThe sorted array for (1, 'Surname')is:\n ",
join ("\n ", &transform_sort (1, 'Surname', @array)),
"\nThe sorted array for (2, 'Surname')is:\n ",
join ("\n ", &transform_sort (2, 'Surname', @array)),
"\nThe sorted array for (2, 'City')is:\n ",
join ("\n ", &transform_sort (2, 'City', @array)),
"\nThe sorted array for (2, 'First name')is:\n ",
join ("\n ", &transform_sort (2, 'First name', @array)),
"\nThe sorted array for (2, 'Country')is:\n ",
join ("\n ", &transform_sort (2, 'Country', @array)),
"\n\n");



waherne
Novice

Jan 8, 2001, 2:33 PM

Post #4 of 7 (762 views)
Re: sort and print [In reply to] Can't Post

rGeoffrey,

Thanks for the efforts you made to write the script. It works perfectly.

I would love to learn some time how it works!

One quick question though, is it possible to identify the variables in the final printed output? For instance, if I selected folder 3 and sort by Surname,would frank, conway, michael, and buckley each have different variable names, e.g. array[2].

The reason I ask is that I want to put each item individual item into a HTML table cell. Therefore, in the above example, I would have a 2 row and 5 column table. Would it be difficult for you to add this feature?

Once again, thanks for what you have done todate, it was excellent.

Willie




rGeoffrey
User / Moderator

Jan 8, 2001, 10:31 PM

Post #5 of 7 (756 views)
Re: sort and print [In reply to] Can't Post

&transform_sort will return an array of rows in your future table. But those rows will again be '|' delimited.

You can use this print statement to print a table with 5 columns and each row that fit already sorted, plus I added the header row at the top.


Code
print ("\nThe sorted table for (3, 'Surname')is:\n<table>\n"); 

foreach ('Folder|First name|Surname|City|Country',
&transform_sort (3, 'Surname', @array)) {
print ('<tr>',
(map { "<td>$_</td>\n" } split ('\|', $_)),
"</tr>\n");
}
print ("</table>\n");

The foreach loops through each row and and prints the '<tr>' tags. And then to get the individual columns we again split on '|' and wrap '<td>' tags around each cell.

To help see what the map is doing compare it to this version that uses foreach row around foreach column


Code
print ("\nThe sorted table for (3, 'Surname')is:\n<table>\n"); 
foreach my $row ('Folder|First name|Surname|City|Country',
&transform_sort (3, 'Surname', @array)) {
print '<tr>';
foreach my $col (split ('\|', $row)) {
print "<td>$col</td>\n";
}
print "</tr>\n";
}



waherne
Novice

Jan 9, 2001, 6:31 AM

Post #6 of 7 (749 views)
Re: sort and print [In reply to] Can't Post

Thanks again rGeoffrey,

I will try the code tonight.

The reason I asked about identifying the variable is because I want to put a link on the surname (in addition to the table issue).

For instance, if the surname is murphy, the link would be murphy underlined. When someone clicks on the link, a script would be called
e.g. cgibin/script.pl?surname=murphy&city=dublin

I will understand if this is too much to ask.

Take care,

Willie





rGeoffrey
User / Moderator

Jan 12, 2001, 8:45 PM

Post #7 of 7 (732 views)
Re: sort and print [In reply to] Can't Post

To make a slightly more complicated table cell you can get the columns for each row, and then replace the cell before you print it.

This will build the link you wanted...


Code
print ("\nThe original array is:\n  ", 
join ("\n ", @array),
"\nThe sorted table for (3, 'Surname')is:\n<table>\n");

print ('<tr>',
(map {"<th>$_</th>\n"} split ('\|', 'Folder|First name|Surname|City|Country')),
"</tr>\n");

foreach my $row (&transform_sort (3, 'Surname', @array)) {
my @cols = split ('\|', $row);
$cols[2] = "<a href=\"cgibin/script.pl?surname=$cols[2]&city=$cols[3]\">$cols[2]</a>";
print ('<tr>',
(map {"<td>$_</td>\n"} @cols),
"</tr>\n");
}
print ("</table>\n");

---
Sun Sep 9, 2001 - 1:46:40 GMT, a very special second in the epoch. How will you celebrate?

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives