Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Descending Sort

by Devo (Initiate)
on Nov 03, 2001 at 09:26 UTC ( [id://123012]=perlquestion: print w/replies, xml ) Need Help??

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

First of all, let me thank everyone involved with this site for maintaining a worthwhile place in on the net.

The problem I'm having is of the "sort" variety. The snippet of code below seems to work fine when sorting numbers or strings. However, it doesn't seem to recognize any kind of descending order sorting.

I am really only concerned with sorting numbers, as in the "else if" statement. When I invert $a and $b, such as:

$result = $b_items[$item_no] <=> $a_items[$item_no];}

it still sorts them as ascending.


Thanks in advance.
sub sort_func { #local($a, $b) = @_; my(@a_items) = split("\t", $a,$datafields); my(@b_items) = split("\t", $b, $datafields); my($item_no) = $sort; # the number of the field to # sort on. my($result) = 0; # default is equal if ($sortby eq "string"){ $result = $a_items[$item_no] cmp $b_items[$item_no]; } elsif ($sortby eq "number"){ $result = $a_items[$item_no] <=> $b_items[$item_no];} return($result); }

Replies are listed 'Best First'.
Re: Descending Sort
by blackmateria (Chaplain) on Nov 03, 2001 at 10:38 UTC
    Without seeing your test data or the way you're calling sort_func, it's hard to tell exactly what's going on. I tried it with this setup:
    #!/usr/bin/perl -w use strict ; my @array = ( "row #1\t106\thello", "row #2\t101\tgoodbye", "row #3\t104\thi again!" ) ; my $datafields = 3 ; my $sort = 1 ; my $sortby = "number" ; print join ("\n", sort {&sort_func} @array) ;

    This appears to work for both cases you mentioned. I don't think it's a precedence bug either. My guess is that one of your multitude of control variables is fouled up (this seems especially likely for $sortby -- doing a case-sensitive comparison with "magic" multi-character literal strings is dangerous, especially with no default case to catch mistakes.) With that said, why use a separate subroutine at all?

    my $col = 1 ; # this is called "$sort" and "$item_no" in the original my @sorted = sort {(split ("\t", $b)) [$col] <=> (split ("\t", $a)) [$ +col]} @array ;

    Like I said, I don't have your test data so that might be totally useless to you, but it does work with the test data I used above (of course your original worked for me too). HTH!

Re: Descending Sort
by mkmcconn (Chaplain) on Nov 05, 2001 at 11:45 UTC

    Hi Devo, and welcome to PerlMonks.

    I think that your specific question can be answered by reading more about sort and reverse. I suspect that your problem is not limited to the title of this node.(Descending Sort)

    More generally, here are some obserations about your code.

    • You try to avoid using the special variables '$a' and '$b', since they sometimes have special meaning, especially when dealing with sort; it's good to comment that out.
    • Following a similar strategy, try to keep variables local to the scope, unless there's a good reason not to. For example, your '$sortby' variable appears to have come from outside the function you've written. It is often better, though, to pass the variable as an argument to the function call. Like this:
      my $adata = q(athings1 athings2); my $bdata = q(bthings1 bthings2); my $column = 0; # ... sort_func($column,$adata,$bdata); sub sort_func { my ($sortby,$astring,$bstring) = @_; # this function uses three arguments. }
    • Your function is returning the result of the 'cmp' and '<=>', in a string. The '$result' will then contain -1, 0, or 1. Is that what you wanted? It may be - but then, shouldn't you just split the strings and sort them, dispensing with the need of 'sort_func()'? Then, no more need for non-local variables, that I can see. To learn more about the comparison operators, read perlop.
    • It appears that you are testing equivalence between two values, not actually attempting to sort. Did you mean to write something like this?
      if ($sortby eq "string"){ my $result = sort { $b cmp $a } ($a_items[$item_no], $b_items[$item +_no]); } # $result will contain the greater of the two values.
    • Also, I'm not sure your split will do what you think it will as written. At least, I assume so because you've put a variable called '$datafields' in the 'LIMIT' argument of split. That means that if $datafields is 2, all the columns after the first column will be excluded from split. That's fine if there are only two columns (in which case, leave out the LIMIT), but what if you had three? So, I'd recommend renaming '$datafields' to '$exclude' or something more descriptive of what it does.
    • However, on the assumption that you want to exclude all but a select number of columns of data from split (a good practice), then you might mean to remove that excluded data. I assume this because you seem to want to sometimes sort things numerically - which would never be applicable if the contents of the final element of the array is "111\t222\t333". In other words, if you really meant to limit your split, then you need to jettison the irrelevant data.
      my @a_items = split("\t", $astring,$limit); #store the remainder my $a_remainder = pop @a_items; my @b_items = split("\t", $bstring,$limit); #discard the remainder pop @b_items;

    I hope this isn't over-doing the answer (a lot of guessing at your intent) but, it appears that some of these observations might be relevant to why you aren't getting the result that you want.
    mkmcconn

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://123012]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (3)
As of 2024-04-18 19:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found