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

Hi all, I'm relatively new to Perl, and need to write a program that sorts the records in a text file in asceding order. The file will contain data like...
15/19/2001 BA A ......
10/19/2001 BA B ......
12/19/2001 BA A ......
11/19/2001 BA A ......
and I would like to sort the records in the order of the first column. So, the above 4 rows should appear as...
10/19/2001 BA B ......
11/19/2001 BA A ......
12/19/2001 BA A ...... 
15/19/2001 BA A ......
Can someone please point me in the right direction? Many thanks in advance.
Harry

Edit kudra, 2001-11-09 Added some markup

Replies are listed 'Best First'.
Re: Sorting rows in a text file
by davorg (Chancellor) on Nov 09, 2001 at 16:17 UTC

    When you submitted this question, did you see some text that said:

    If something looked unlike you expected it to you might need to check out Writeup Formatting Tips

    Did the node look like you expected it to? I doubt it.

    To answer your question, sorting in Perl is done using the (strangely named) sort function. You might like to look at the docs for that function.

    Your sort seems pretty basic. Assuming you've opened a filehandle called INPUT you can get a sorted list of records like this:

    my @data = sort <INPUT>;

    By the way, are those supposed to be dates. You might like to give them a closer look :)

    Update: To clarify. The data does look like dates, but at least one of them is invalid. All of the others are only valid if you assume MM/DD/YYYY format. If that's the case, then sort sorted example seems a bit strange as you'd be sorting by month, then day, then year which would give bizarre results with a full set of data. Given those facts, together with the fact that the sorted example shows the data sorted in ascii-betical order, I chose to show a simple sort (that gives the right answer with the sample date) and a link to the docs for sort that would be helpful for more complex sorts.

    If the data is, in fact, dates, then thinker's answer is, of course, better. However, it's a little inefficient and a Schwartzian transform might be more appropriate.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you don't talk about Perl club."

Re: Sorting rows in a text file
by thinker (Parson) on Nov 09, 2001 at 19:18 UTC
    Hi saihuj,

    This code is by no means robust, but it should work if the data files are in _exactly_ the form you state.

    Also, I am not sure whether 15/19/2001 means the 15th day of the 19th month, or vice versa. Whatever, that month is out of scale in my planet :-). So I assume dd/mm/yy

    Oh, and it doesn't check the integrity of dates :-). Did I mention that.

    Still, I hope the sort code can help you become familiar with how things work.

    #!/usr/bin/perl -w use strict; open DATA, "./data.txt"; # or wherever the file is my @data=<DATA>; my @sorted = sort sort_func @data ; for(@sorted){print $_}; sub sort_func{ my ($a_dd,$a_mm,$a_yy)=$a =~ m|(\d*)/(\d*)/(\d*)|; my ($b_dd,$b_mm,$b_yy)=$b =~ m|(\d*)/(\d*)/(\d*)|; return ( $a_yy<=>$b_yy || $a_mm<=>$b_mm || $a_dd<=>$b_dd); }
    cheers

    thinker
      thinker's solution is perfectly valid. However it's probably not the most efficient way to do it. This may be a concern if you have a lot of data.

      So, I'll suggest using a Schwartzian Transform (an algorithm created by our very own merlyn).

      untested code:

      #!/usr/bin/perl -w use strict; open (DATA, "./data.txt") or die $!; # for example my @sorted = map { $_->[1] } sort { $a->[0] cmp $b->[0] } map { [ &fix_date($_), $_ ] } <DATA>; for (@sorted) { print $_ }; sub fix_date { my ($d,$m,$y) = ( shift =~ m|(\d\d)/(\d\d)/(\d{4})| ); return "$y-$m-$d"; }
      The basic speed eater for thinker's way is that you have to munge the date to sort it a great number of times.

      The first (lower) map does the time expensive data munging, into a form that's easy for sort to deal with, and the last (top) map puts the data back into the original form

      HTH

      /\/\averick
      perl -l -e "eval pack('h*','072796e6470272f2c5f2c5166756279636b672');"