http://www.perlmonks.org?node_id=918353


in reply to Sorting dates with the Schwartzian Transform

A Schwartzian Transform when all you have to do is parse dates? That will make things *slower*. Creating all those arrays and references adds up.

This could speed up the sorting (because it creates few extra variables and it uses the specially optimised $a cmp $b callback):

my @sorted = map substr($_, 8), sort map join('', (/(..)-(..)-(....)/)[2,1,0], $_), @dates; # DD-MM-YYYY

Naïve:

my @sorted = sort { join('', ($a =~ /(..)-(..)-(....)/)[2,1,0]) cmp join('', ($b =~ /(..)-(..)-(....)/)[2,1,0]) } @dates; # DD-MM-YYYY

Schwartzian Transform:

my @sorted = map $_->[0], sort { $a->[1] cmp $b->[1] } map [ $_, join('', (/(..)-(..)-(....)/)[2,1,0]) ], @dates; # DD-MM-YYYY

Replies are listed 'Best First'.
Re^2: Sorting dates with the Schwartzian Transform
by Wobbel (Acolyte) on Aug 03, 2011 at 19:11 UTC

    Dear Perl experts, thanks for all the usefull replies and different approaches! The PerlMonks website is a real good place to learn new things and why you choose a certain solution. Great.

    The sorting is not only about dates. Patient_ID, Course_ID, Session_number, Session_date, Imaging_type, and a lot of measurements. The sorting question is the last part of a bigger project. "The doctor" needs the data in an Excel-friendly format :-( .

    I can't wait to fine tune my code, but I'll have to wait till tomorrow.

Re^2: Sorting dates with the Schwartzian Transform
by Wobbel (Acolyte) on Aug 15, 2011 at 13:19 UTC

    I'm so close to the last step, but....

    What if you sort on two or three special columns? In my case date 11 and time 12. Is your original code limited to one column, our is it possible to "map" on more then one time/date format?

    I've Googled and tried a lot last week, but I'm stuck (on the syntaxis).

    my @sorted = map $_->[0], sort { $a->[11] cmp $b->[11] || #Date, original # $a->[12] cmp $b->[12] #Time, to do list } map [ $_, join('', (/(..)-(..)-(....)/)[2,1,0]) ], # map [ $_, join('', (/(..):(..):(..)/)[2,1,0]) ], # Is it possible + to map two columns date and time? @dates; # DD-MM-YYYY # HOURS:MIN:SEC

      I've Googled and tried a lot last week, but I'm stuck (on the syntaxis).

      I hope you understand my message despite the wording

      Actually it seems more like you're stuck on syntax and arrays.

      You need to read perlintro and Basic debugging checklist and How do I post a question effectively? and References quick reference

      Also, when you have a program, with real, named variables, talking about columns can get confusing , talk about your variables instead ;)

      The code you pasted will never have a 12 element array, nor do you want one.

      I would go back to

      my @sorted = map substr($_, 8), sort map join('', (/(..)-(..)-(....)/)[2,1,0], $_), @dates; # DD-MM-YYYY
      Don't get it? To understand, you would write a program like this
      #!/usr/bin/perl -- use strict; use warnings; use Data::Dumper; my @dates = qw[ 08-15-2011 08-10-2011 08-05-2011 ]; print "\ndates ", Dumper( \@dates ); #~ my @firstTransform = map join('', (/(..)-(..)-(....)/)[2,1,0], $_) +, @dates; # DD-MM-YYYY my @firstTransform = map join('', ReorderForCmp($_), $_), @dates; # +DD-MM-YYYY print "\nfirstTransform ", Dumper( \@firstTransform ); my @firstSorted = sort @firstTransform ; print "\nfirsSorted ", Dumper( \@firstSorted ); my @finalTransform = map substr($_, 8), @firstSorted ; print "\nfinalTransform ", Dumper( \@finalTransform ); sub ReorderForCmp { my( $one ) = @_; my @date = $one =~ /(..)-(..)-(....)/; #~ return @date[2,1,0]; return $date[2], $date[1], $date[0]; } __END__
      which produces this output
      dates $VAR1 = [ '08-15-2011', '08-10-2011', '08-05-2011' ]; firstTransform $VAR1 = [ '2011150808-15-2011', '2011100808-10-2011', '2011050808-05-2011' ]; firsSorted $VAR1 = [ '2011050808-05-2011', '2011100808-10-2011', '2011150808-15-2011' ]; finalTransform $VAR1 = [ '08-05-2011', '08-10-2011', '08-15-2011' ];
      So yes, it is possible to "map two columns date and time", just adjust sub ReorderForCmp to return iso-8601 style datetime ( YYYYMMDDHHMMSS)

        I think it is time to make some excuses. I guess I'm a little bit desperate because of complete exhaustion. The last nine years I wrote a couple of Perlscripts and read/practised on a regular basis. Even our first two babyboys were no problem at all. But since eleven weeks, we got a lovely babygirl.

        Sleep(10000); doesn't work for her....

        If I look at my old code, It's easy to understand.

        But a new improvent with only a half line of code...(OK, three lines. I'm not a pro)

        I just don't see it anymore!

        Thanks for your patience and the advice / links. I know them all and a few more.

        Let me sleep for a week in a monastery or so and I will finish the last lines of code :-) .