Connecting Tech Pros Worldwide Forums | Help | Site Map

Secondary sorting keys

Member
 
Join Date: Jul 2007
Posts: 40
#1: Jul 31 '07
my flat field DB fields are: [Name,Code,Category]

I have them sorted by field [3] (category=TeachersActivity or ChildrensBooks) so they are grouped together as Children's Books then Teacher Activities

Expand|Select|Wrap|Line Numbers
  1. open(BASE, $dbk) || do {&no_open;};
  2. my @sorted = <BASE>;
  3. close(BASE);
  4.  
  5. foreach my $line (sort cat @sorted) {
  6.     my @show = split ',', $line;
  7.  
  8.  
  9. ....
  10.  
  11. sub cat {
  12.     @x = split ',', $a;
  13.     @y = split ',', $b;
  14.     return ($x[2] cmp $y[2]);
  15. }
the result is:

Expand|Select|Wrap|Line Numbers
  1. Children and Their World - Children's Books
  2. Nature - Children's Books
  3. Animals - Children's Books
  4. Families - Children's Books
  5. Learning About Myself - Children's Books
  6. Thinking Skills - Children's Books
  7. Multicultural Book - Children's Books
  8. Arts and Crafts - Teacher Activities
  9. Cooking Activities - Teacher Activities
  10. Creative Activities - Teacher Activities
  11. Preschool Activities - Teacher Activities
  12. Child Guidance - Teacher Activities
  13.  

Is there a way to further sort them so that each 'group' Children's Books or Teacher Activities would be in alphabetical order, so the result would be:

Expand|Select|Wrap|Line Numbers
  1. Animals - Children's Books
  2. Children and Their World - Children's Books
  3. Families - Children's Books
  4. Learning About Myself - Children's Books
  5. Multicultural Book - Children's Books
  6. Nature - Children's Books
  7. Thinking Skills - Children's Books
  8. Arts and Crafts - Teacher Activities
  9. Child Guidance - Teacher Activities
  10. Cooking Activities - Teacher Activities
  11. Creative Activities - Teacher Activities
  12. Preschool Activities - Teacher Activities
  13.  
thanks
Paul
miller's Avatar
Moderator
 
Join Date: Oct 2006
Location: San Francisco, CA
Posts: 830
#2: Jul 31 '07

re: Secondary sorting keys


Yes, just add the other conditions to your sorting function:

Expand|Select|Wrap|Line Numbers
  1. open(BASE, $dbk) || do {&no_open;};
  2. my @dbk = <BASE>;
  3. close(BASE);
  4.  
  5. foreach my $line (sort cat @sorted) {
  6.     my @show = split ',', $line;
  7.     print "@show";
  8. }
  9.  
  10. sub cat {
  11.     @x = split ',', $a;
  12.     @y = split ',', $b;
  13.     return ($x[2] cmp $y[2]) || ($x[0] cmp $y[0]);
  14. }
  15.  
- Miller
KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#3: Jul 31 '07

re: Secondary sorting keys


use a Schwartzian Transform:

Expand|Select|Wrap|Line Numbers
  1. open (BASE, $dbk) || do {&no_open;};
  2. @sorted = <BASE>;
  3. close BASE;
  4. @sortedNew = map  {"$_->[0] - $->}[2]"}
  5.              sort {$a->[2] cmp $b->[2] || $a->[0] cmp $b->[0]}
  6.              map  {chomp; [split(/,/)]} @sorted;
  7. print "$_\n" for @sortedNew;
  8.  
http://www.stonehenge.com/merlyn/UnixReview/col64.html
KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#4: Jul 31 '07

re: Secondary sorting keys


Quote:

Originally Posted by miller

Yes, just add the other conditions to your sorting function:

Expand|Select|Wrap|Line Numbers
  1. open(BASE, $dbk) || do {&no_open;};
  2. my @dbk = <BASE>;
  3. close(BASE);
  4.  
  5. foreach my $line (sort cat @sorted) {
  6.     my @show = split ',', $line;
  7.     print "@show";
  8. }
  9.  
  10. sub cat {
  11.     @x = split ',', $a;
  12.     @y = split ',', $b;
  13.     return ($x[2] cmp $y[2]) || ($x[0] cmp $y[0]);
  14. }
  15.  
- Miller

Looks like it would be fairly slow, but if the file is not big it may not matter.
Member
 
Join Date: Jul 2007
Posts: 40
#5: Jul 31 '07

re: Secondary sorting keys


thanks a lot!
many thanks
Paul
Member
 
Join Date: Jul 2007
Posts: 40
#6: Jul 31 '07

re: Secondary sorting keys


One more question.
The result of the sort is:

Animals - Children's Books
Children and Their World - Children's Books
Families - Children's Books
Learning About Myself - Children's Books
Multicultural Book - Children's Books
Nature - Children's Books
Thinking Skills - Children's Books
Arts and Crafts - Teacher Activities
Child Guidance - Teacher Activities
Cooking Activities - Teacher Activities
Creative Activities - Teacher Activities
Preschool Activities - Teacher Activities

which is perfect.
I have the output going into a table, is there a way to split the output to 2 columns instead of one long column.
I would like to have Children's Books displayed in the first column and Teachers Activities in the 2nd column.

I have tried a few things and all I get is something like this:

-------------[column 1]--------------------------------------------------[column 2]
Animals - Children's Books---------------------------------Arts and Crafts - Teacher Activities
Children and Their World - Children's Books-----------(blank cell)
Families - Children's Books--------------------------------(blank cell)
Learning About Myself - Children's Books---------------Child Guidance - Teacher Activities
Multicultural Book - Children's Books---------------------Cooking Activities - Teacher Activities
Nature - Children's Books-----------------------------------(blank cell)
Thinking Skills - Children's Books-------------------------Creative Activities - Teacher Activities
--------------------------------------------------------------------Preschool Activities - Teacher Activities

I'm sure I did it once, but maybe not.
Any help would be appreciated.

thanks
Paul
miller's Avatar
Moderator
 
Join Date: Oct 2006
Location: San Francisco, CA
Posts: 830
#7: Jul 31 '07

re: Secondary sorting keys


For ultra simple text formatting, use sprintf:

Expand|Select|Wrap|Line Numbers
  1. my @lines = (
  2.     "hello world - what'cha doing today?\n",
  3.     "foo bar baz biz lama lama - oh yeah\n",
  4.     "eek - more spacing tests\n",
  5. );
  6.  
  7. foreach my $line (@lines) {
  8.     my ($col1, $col2) = split ' - ', $line;
  9.     print sprintf("%-30s %s", $col1, $col2);
  10. }
  11.  
- Miller
miller's Avatar
Moderator
 
Join Date: Oct 2006
Location: San Francisco, CA
Posts: 830
#8: Jul 31 '07

re: Secondary sorting keys


Quote:

Originally Posted by KevinADC

Looks like it would be fairly slow, but if the file is not big it may not matter.

I would call it just "slower". In truth, even for a large data file, I expect that the perl sorting and splitting functionality would be plenty fast enough for this to not be a noticable operation.

But either way, it just seemed simpler to avoid algorithmic efficiency discussions, and just focus on how one does this in a basic way. Yes, we probably wouldn't do it that way. But he didn't ask how we would, just how "one would". :)

- M
KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#9: Jul 31 '07

re: Secondary sorting keys


Quote:

Originally Posted by deppeler

I have tried a few things and all I get is something like this:

Lets see something you have tried. "Table" could mean just about anything.
Member
 
Join Date: Jul 2007
Posts: 40
#10: Aug 1 '07

re: Secondary sorting keys


Here is one I tried:

Expand|Select|Wrap|Line Numbers
  1. <table width='100%' border='1' cellpadding='1' cellspacing='1'>
  2. HTML
  3. open (BASE, $dbk) || do {&no_open;};
  4. @sorted = <BASE>;
  5. foreach $line (sort cat @sorted) {
  6.     @show = split(/,/,"$line");
  7.     $showta = "";
  8.     $showta = "$show[0]" if $show[2] eq 'Teacher and Activity Books';
  9.     $showcb = "";
  10.     $showcb = "$show[0]" if $show[2] eq 'Children`s Books';
  11.     print "<tr><td align='left' width='365'>$showta</td><td width='364'>$showcb</td></tr>";
  12. }
  13. close(BASE);
  14.  
  15. sub cat {
  16.     @x = split(/,/,$a);
  17.     @y = split(/,/,$b);
  18.     return ($x[2] cmp $y[2]) || ($x[0] cmp $y[0]);
  19. }
  20.  
  21. print <<"HTML";
  22. </table>

and this gives me an output of this:



instead of this:



thanks
Paul
KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#11: Aug 1 '07

re: Secondary sorting keys


what you want to do would best, or most easily, be accomplished by two arrays and using a different html table structure. This is untested and not meant to be a complete solution but I think it gives you the basic concept:

Expand|Select|Wrap|Line Numbers
  1. my @c = ();
  2. my @t = ();
  3. open (BASE, $dbk) || do {&no_open;};
  4. my @sorted = <BASE>;
  5. close (BASE);
  6. foreach $line (@sorted) {
  7.    if ($line =~ /Teacher and Activity Books/) {
  8.       push @t, $line;
  9.    }
  10.    else {
  11.       push @c, $line;
  12.    }
  13. }
  14. @t = sort @t;
  15. @c = sort @c;
  16. my ($ctable,$ttable) = (q{<table width='100%' border='1'>}, q{<table width='100%' border='1'>});
  17. for (@c){
  18.    $ctable .= qq{<tr><td>$_</td></tr>\n};
  19. }
  20. for (@t){
  21.    $ttable .= qq{<tr><td>$_</td></tr>\n};
  22. }
  23. $ctable .= '</table>';
  24. $ttable .= '</table>';
  25. print qq{<table width='100%' border='0' cellpadding='1' cellspacing='1'>
  26.  <tr>
  27.   <td valign="top" width="50%">
  28.     $ctable
  29.   </td>
  30.   <td valign="top" width="50%">
  31.     $ttable
  32.   </td>
  33.  </tr>
  34. </table>\n};
this is not the way I would probably do it, but unless you are ready to get into references and more complex data structres, like a hash of arrays and such, then a solution like this while a little awkward is fairly straight forward to understand.

-Kevin
Member
 
Join Date: Jul 2007
Posts: 40
#12: Aug 1 '07

re: Secondary sorting keys


No that looks good except how do I stop it printing the entire line of the db?
I just want the field 1 & 2 and not the commas either.
It prints like this:
Animals,ANIML,Children's Books,

I would like it to print like this:
Animals - Children's Books

thanks a heap
Paul
KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#13: Aug 1 '07

re: Secondary sorting keys


Like I said, not a complete solution. Use split() to get the parts of the lines you want just like you have been doing in your previous code.
Member
 
Join Date: Jul 2007
Posts: 40
#14: Aug 1 '07

re: Secondary sorting keys


Ok I tried:

Expand|Select|Wrap|Line Numbers
  1. my @c = ();
  2. my @t = ();
  3. open (BASE, $dbk) || do {&no_open;};
  4. my @sorted = <BASE>;
  5. close (BASE);
  6. foreach $line (@sorted) {
  7. @show = split ',', $line;
  8.    if ($line =~ /Teacher and Activity Books/) {
  9.       push @t, $line;
  10.    }
  11.    else {
  12.       push @c, $line;
  13.    }
  14. }
  15. @t = sort @t;
  16. @c = sort @c;
  17. my ($ctable,$ttable) = (q{<table width='362' border='0' cellpadding='3' cellspacing='1' align='center' bgcolor='#F5F5F5'>}, q{<table width='361' border='0' cellpadding='3' cellspacing='1' align='center' bgcolor='#F5F5F5'>});
  18. for (@c){
  19.    $ctable .= qq{<tr><td>$show[0] - $show[2]</td></tr>\n};
  20. }
  21. for (@t){
  22.    $ttable .= qq{<tr><td>$show[0] - $show[2]</td></tr>\n};
  23. }
  24. $ctable .= '</table>';
  25. $ttable .= '</table>';
  26. print qq{<table width='729' border='0' cellpadding='3' cellspacing='1' align='center' bgcolor='#F5F5F5'>
  27.  <tr>
  28.   <td valign="top" width="50%">
  29.     $ctable
  30.   </td>
  31.   <td valign="top" width="50%">
  32.     $ttable
  33.   </td>
  34.  </tr>
  35. </table>\n};

But I am only get the first line repeated.
What am I doing wrong?

thanks
KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#15: Aug 2 '07

re: Secondary sorting keys


You have a fundamental misunderstanding of the process. See how this works:

Expand|Select|Wrap|Line Numbers
  1. my @c = ();
  2. my @t = ();
  3. open (BASE, $dbk) || do {&no_open;};
  4. my @sorted = <BASE>;
  5. close (BASE);
  6. foreach $line (@sorted) {
  7.    if ($line =~ /Teacher and Activity Books/) {
  8.       push @t, $line;
  9.    }
  10.    else {
  11.       push @c, $line;
  12.    }
  13. }
  14. @t = sort @t;
  15. @c = sort @c;
  16. my ($ctable,$ttable) = (q{<table width='100%' border='1'>}, q{<table width='100%' border='1'>});
  17. for (@c){
  18.    my @temp = split(/,/);
  19.    $ctable .= qq{<tr><td>$temp[0] - $temp[2]</td></tr>\n};
  20. }
  21. for (@t){
  22.    my @temp = split(/,/);
  23.    $ttable .= qq{<tr><td>$temp[0] - $temp[2]</td></tr>\n};
  24. }
  25. $ctable .= '</table>';
  26. $ttable .= '</table>';
  27. print qq{<table width='100%' border='0' cellpadding='1' cellspacing='1'>
  28.  <tr>
  29.   <td valign="top" width="50%">
  30.     $ctable
  31.   </td>
  32.   <td valign="top" width="50%">
  33.     $ttable
  34.   </td>
  35.  </tr>
  36. </table>\n}; 
Reply