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

I am a noob that has come looking for sage advice. Here is the data that I am trying to work with.

RRsnap02  2013-07-24 12:35:35
vmk000    2013-07-22 17:16:50
vmk001    2013-07-22 20:00:36
vmk009    2013-07-23 18:21:12
vmk010    2013-07-23 18:31:00
vmk020    2013-07-23 23:30:43
vmk024    2013-07-24 03:27:30
vmk031    2013-07-24 10:27:36
vmk032    2013-07-24 11:27:38
vmk032    2013-07-24 11:27:38

What I'm trying to do is an ascending sort through this list, maintaining the name associated with each timestamp.

Thanks in advance.
Sparky

Replies are listed 'Best First'.
Re: sort timestamps with associated names.
by choroba (Cardinal) on Jul 25, 2013 at 13:35 UTC
    There is more than one way to do it:
    #!/usr/bin/perl use warnings; use strict; my @data = ('RRsnap02 2013-07-24 12:35:35', 'vmk000 2013-07-22 17:16:50', 'vmk001 2013-07-22 20:00:36', 'vmk009 2013-07-23 18:21:12', 'vmk010 2013-07-23 18:31:00', 'vmk020 2013-07-23 23:30:43', 'vmk024 2013-07-24 03:27:30', 'vmk031 2013-07-24 10:27:36', 'vmk032 2013-07-24 11:27:38', 'vmk032 2013-07-24 11:27:38', ); sub get_date { my $s = shift; $s =~ s/^\S+\s+//; return $s; } # Simple: print "$_\n" for sort { get_date($a) cmp get_date($b) } @data; # Faster, Schwartzian transform, computes get_date just once for each +line: print "$_\n" for map $_->[1], sort { $a->[0] cmp $b->[0] } map [ get_date($_), $_ ], @data; # Orcish maneuver, compute get_date only when needed and cache: my %cache; print "$_\n" for sort { ( $cache{$a} //= get_date($a) ) cmp ( $cache{$b} //= get_date($b) ) } @data; # Guttman Rosler Transform, changing to strings for default sort: print "$_\n" for map { s/(.*) (\S+\s+)$/$2$1/; $_ } sort map { s/^(\S+\s+)(.*)/$2 $1/; $_ } @data;
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Instead of get_date($_) you can use /(.{19})$/.

      ++ for a very informative answer. Have just been playing with Sort::Maker that will return a sub reference encapsulating any of the four types of sorting routines you ably demonstrated above. While it's not much savings for the plain case, you can alter your choice by changing one keyword:
      use Sort::Maker; print make_sorter(qw/plain string substr($_,10)/)->(<DATA>); __DATA__ RRsnap02 2013-07-24 12:35:35 vmk000 2013-07-22 17:16:50 vmk001 2013-07-22 20:00:36 vmk009 2013-07-23 18:21:12 vmk010 2013-07-23 18:31:00 vmk020 2013-07-23 23:30:43 vmk024 2013-07-24 03:27:30 vmk031 2013-07-24 10:27:36 vmk032 2013-07-24 11:27:38 vmk032 2013-07-24 11:27:38
      The generated code is straight forward:
      sort { do{ my( $left, $right ) = map { substr($_,10) } $a, $b; $left cmp $right } } @_;
      You could replace 'plain' with 'orcish', 'ST', or 'GRT' -- and for the ST case, the generated code is:
      return map $_->[0], sort {$a->[1] cmp $b->[1]} map [ $_, do{ my ($val) = substr($_,10) ; $val } ], @_ ;
Re: sort timestamps with associated names.
by hdb (Monsignor) on Jul 25, 2013 at 13:40 UTC

    Some hints how I would solve this:

    1. Your date format yyyy-mm-dd hh:mm:ss is already suitable for lexographical sorting, no need to change the format.
    2. The date is the last 19 characters of each line, so it can be extracted easily using either a regex or substr.
    3. If you read line by line, don't forget to chomp;
    4. The Schwartzian Transform is one way to approach this. Read here: Understanding the Schwartzian transform.

Re: sort timestamps with associated names.
by Loops (Curate) on Jul 25, 2013 at 14:14 UTC
    use strict; use warnings; print sort { ($a =~ m/\S+\s+(.+)$/)[0] cmp ($b =~ m/\S+\s+(.+)$/)[0] } + <DATA>; __DATA__ vmk032 2013-07-24 11:27:38 RRsnap02 2013-07-24 12:35:35 vmk000 2013-07-22 17:16:50 vmk001 2013-07-22 20:00:36 vmk009 2013-07-23 18:21:12 vmk010 2013-07-23 18:31:00 vmk020 2013-07-23 23:30:43 vmk024 2013-07-24 03:27:30 vmk031 2013-07-24 10:27:36 vmk032 2013-07-24 11:27:38
Re: sort timestamps with associated names.
by zwon (Abbot) on Jul 25, 2013 at 13:32 UTC
    Welcome to the monastery. Can you tell us how are you trying to do this and what is exactly you are experiencing difficulties with? See also How (Not) To Ask A Question.
Re: sort timestamps with associated names.
by salva (Canon) on Jul 26, 2013 at 08:43 UTC
    Your data seems to use fixed length records, so you can just use substr to extract the timestamp fragment:
    my @sorted = sort { substr($a, 10) cmp substr($b, 10) } @data;
      Thank you to all that replied. The suggestions helped.
Re: sort timestamps with associated names.
by Laurent_R (Canon) on Jul 25, 2013 at 19:04 UTC

    Hmm, you did not say on what you want to sort your data (date? name of the first field? other?) and also did not say whether your data is in a Perl array, in a file, etc.

    So the answer to your question could just be:

    my @sorted_records = sort @unsorted_record;

    This will sort "ASCIIbetically" the array in ascending order. If you need something else, why don't you explain it?

      I find the title "sort timestamps with associated names" rather suggestive...

Re: sort timestamps with associated names.
by hdb (Monsignor) on Jul 26, 2013 at 08:34 UTC

    Just for fun and not to be taken too seriously, here is a "Pseudo-Schwartzian" solution:

    use strict; use warnings; print map { /^(.{19})(.*)$/; "$2$1\n" } sort map { /^(.*)(.{19})$/; + "$2$1" } <DATA>; __DATA__ RRsnap02 2013-07-24 12:35:35 vmk000 2013-07-22 17:16:50 vmk001 2013-07-22 20:00:36 vmk009 2013-07-23 18:21:12 vmk010 2013-07-23 18:31:00 vmk020 2013-07-23 23:30:43 vmk024 2013-07-24 03:27:30 vmk031 2013-07-24 10:27:36 vmk032 2013-07-24 11:27:38 vmk032 2013-07-24 11:27:38

    UPDATE: -- for me for not realizing that choroba had posted the same thing above already: Re: sort timestamps with associated names.

      This is not ST, it is Guttman Rosler.
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ