m.y has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks, I have an array of lines that I would like to sort. The lines have fields which are separated by a single space. There are many fields in a line but I would like to sort the array only by the first two fields. The first field is a timestamp (from localtime()), the second field is a capital letter (ie A-Z). Can someone tell me how I can perform such a sort ? thanks

Replies are listed 'Best First'.
Re: Sorting question
by morgon (Priest) on May 27, 2009 at 23:58 UTC
    One way to do it (this is a standard technique called a Schwarzian Transformation) all in one go:
    my @sorted_array = map { $_->{line} } # extract the lines again sort { # do the sorting $a->{ts} <=> $b->{ts} || $a->{letter} cmp $b->{letter} } map { # build a data-structure that we can sort on my ($ts, $letter) = split / /; { line => $_, ts => $ts, letter => $letter } } @array_to_sort;
    This assumes you want to first sort on timestamps (numerical order) and then on the letters (string-order).

    Tweak the sort expression accordingly if you require something else.

Re: Sorting question
by ig (Vicar) on May 28, 2009 at 01:54 UTC

    Assuming you want a chronological sort of your timestamp rather than a lexical sort, you might try something like the following:

    use DateTime::Format::Flexible; my @sorted = map { $_->{line} } sort { $a->{dt} <=> $b->{dt} or $a->{l} cmp $b->{l} } map { { dt => DateTime::Format::Flexible->parse_datetime( substr($ +_,0,24) ), l => substr($_,25,1), line => $_ } } @lines;
Re: Sorting question
by jethro (Monsignor) on May 27, 2009 at 23:59 UTC
    @new= sort { my ($a1,$a2)= split /\s+/,$a; my ($b1,$b2)= split /\s+/,$b; return($a1<=>$b1 or $a2 cmp $b2); } @old;
    should do it (untested). To understand this just do 'perldoc -f sort' to read about the sort function.

    UPDATE: Added the much needed 'sort' key word after getting hints from almut, johngg and shmem