Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Sorting Numbers

by Devo (Initiate)
on Nov 06, 2001 at 06:00 UTC ( #123479=perlquestion: print w/replies, xml ) Need Help??

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

Thanks to everyone who helped me with my previous post on sorting. In response, I would like to add some more information and clarify some of the variables that are being used.

As stated in my last post, I want to sort some numbers in descending order, but can only get this code to sort them ascending. I apologize for the vagueness, but this is not my code...I'm just picking up on a job that another programmer left.
Thanks in advance for any help that can be provided.

$sortby="number"; $sort=2;
foreach $line (sort(sort_func &read_file("DATAFILE"))) close(DATAFILE); 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 = $b_items[$item_no] <=> $a_items[$item_no];} # for nu +mbers return($result); } sub read_file { my ($filevar) = @_; <$filevar>; }

Replies are listed 'Best First'.
(jeffa) Re: Sorting Numbers
by jeffa (Bishop) on Nov 06, 2001 at 07:13 UTC
    I really wish you would have included some sample data - it doesn't have to be the exact data for obvious legal reasons, but just some data of similar structure. This code is quite horrible, it is obvious that someone was attempting to make modular, reusable code, but fell short of the mark.

    Looks like the idea is to sort on the results of a user defined sort routine (that relies on global variable no less) that gets its input from a subroutine that turns its first argument into a filehandle and returns it. This is wrong, wrong, wrong, wrong!

    Instead, you should open the file, process it into a data structure - looks like a 2-d array would be good to me, THEN sort the data structure. The subroutine sort_func is repeatedly splitting the lines to do it's work - this is extremely wasteful, especially if you need the pieces of the lines again later on.

    Here is some sample code to play with. Since you didn't supply any test data (hint hint), i'll make up my own. Also, i am going to use the DATA handle instead of reading from a file. You should have no troubles changing this to fit your needs:

    use strict; my $datafields = 3; my $item_no = 2; my @records; # read from DATA - any filehandle will do . . . foreach my $line (<DATA>) { chomp $line; push @records, [ split(/\s+/,$line,$datafields) ]; } =comment now @records looks like this: @records = ( ['foo','gabba','12'], ['bar','hey','2'], ['baz','gabba','38'] ); the elements in []'s are array references now store the array references based on the order of the 3rd element, which is a number - numbers are compared with the <=> operator, strings are comparted with the cmp operator - $a and $b are magic variables that contain the two items being compared - if you want ascending order, compare $a to $b - for descencing order, compare $b to $a =cut my @sorted = sort { $b->[$item_no] <=> $a->[$item_no] } @records; =comment that's it! now print out the results - the tricky part is that @sorted is a list of list REFERENCES, so we need to do some extra work to de-reference them =cut foreach my $line (@sorted) { print join(', ', @$line), "\n"; } =comment the following would normally be found in a data file. i originally delimited these values with tabs, but they will probably turn into spaces when you copy and paste that's why i used /\s+/ instead of /\t/ in split above =cut __DATA__ foo gabba 12 bar hey 2 baz gabba 38

    Hope this helps, and don't forget to erase the comments when you are done ;)

    (the triplet paradiddle)

    UPDATE - changed multi-line comment style from # to POD

      Yes, I do agree with your idea of simplicity...Open the file, dump in an array, then sort. I would like to solve it in two ways however, and avoid editing so much of the scripts. (This is a series of about 6 different scripts *reaching for aspirin*, all with user defined variables linked together in very odd ways....hence the problem I'm having here).

      The data is tab deliminated and looks like this:

      17 8/10/01 Joe Blow New York webtherapist www.d I like green-eggs and ham,etc...

      That's meant to be perceived as 8 different fields, the first being the number of the entry in which I wish to sort by...descending order of course.

        From the perspective of sheer laziness, would it work to replace the
        "local ($a, $b) = @_"
        with a
        "local ($b, $a) = @_"
        ? Reversed sort order, no comprehension or re-writing required.


        I understand the motive of trying to avoid editing the scripts, Devo, but in the long run if you stick with the previous author's plan, it's too fragile to maintain and impossible to safely extend.

        tilly wrote a nice discussion of Pass by reference vs globals, in a thread of nice discussions that's relevant to the maintenance problem you are facing (thus the need of aspirin)

        The true virtue of laziness is in saving everyone work. It is the most lazy thing, in this case, to edit out the costly, polluting mistakes in that code

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (1)
As of 2023-06-02 02:49 GMT
Find Nodes?
    Voting Booth?

    No recent polls found