如何在Perl中按降序排序dd:mm:yyyy hh24:mi:ss格式的时间戳?

时间:2011-10-10 10:26:36

标签: perl sorting timestamp

我必须按时间戳(dd:mm:yyyy hh24:mi:ss)按降序排序我的哈希键。

sort { $b <=> $a } keys %time_spercent

这种方式并没有让我得到我打算做的事情。相反,即使日期不是这样,这也会以更高的小时和分钟排序结束。例如,正如我所提到的那样,这就是我进行排序的方式。

21:01:2011 16:51:09
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

相反,我希望他们按照这个顺序按日期和时间排列。

05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:48:37
21:01:2011 16:51:09
21:01:2011 16:49:54

任何关于如何做到这一点的建议都会感激不尽。

更新

foreach my $status_date( 
     map  { $_->[0] }
     sort { $b->[1] cmp $a->[1] }
     map  { [$_, sorting_desc($_)] } keys % {$com_sam->{ $s1 } } ) 

sub sorting_desc {
    $_ = shift;
    if (/(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)/) {
        return "$2:$1:$3:$4:$5:$6";
    }
}

是排序的子程序。

我也试过

foreach my $status_date( 
    map  { $_->[0] }
    sort { $b->[1] cmp $a->[1] }
    map { [$_, (split/[:\s][1]] } keys % {$com_sam->{ $s1 } } )

但不是预期的结果。

我得到的只是:

WGA_PD7124a WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192654  01:07:2011 16:13:55
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192655  01:07:2011 16:11:23
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Male(Unknown)   192656  01:07:2011 11:04:26
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184557  04:05:2011 17:34:27
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184557  04:05:2011 17:34:27
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174878  15:02:2011 09:24:31
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174970  15:02:2011 09:21:19
3074    3074    87(10)  87(10)  87      100.00  109     Female(Unknown) 174860  15:02:2011 09:16:32
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173382  09:02:2011 09:54:48
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173284  09:02:2011 09:51:02
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173382  09:02:2011 09:54:48
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173284  09:02:2011 09:51:02
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200946  25:08:2011 10:17:26
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200946  25:08:2011 10:17:26
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179502  23:03:2011 10:03:23
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179470  23:03:2011 10:02:30

5 个答案:

答案 0 :(得分:11)

您可以将格式更改为yyyy:mm:dd hh24:mi:ss吗?那时你有一个自然排序。基本上,将所有内容按重要性递减顺序,对机器友好程度要高得多:)

编辑:然后只需使用字符串比较订购,因为它自然会以正确的方式排序。

答案 1 :(得分:3)

根据您的问题,我不清楚您是如何排序以及如何制作示例的。我无法在您预期的排序顺序示例中检测到任何订单。 可能的解决方案在底部。

让我澄清一下:

给定带有以下内容的文本文件“ts”(您的示例):

> cat ts
21:01:2011 16:51:09
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

标准排序产生以下输出:

> perl -e '@a = <>; print sort @a' ts
05:04:2011 11:48:37
05:04:2011 11:48:37
05:04:2011 11:51:13
05:04:2011 11:51:13
21:01:2011 16:49:54
21:01:2011 16:51:09
26:01:2011 11:01:40
26:01:2011 11:02:55

虽然您提出的数字下降排序产生以下顺序:

> perl -e '@a = <>; print sort { $b <=> $a } @a' ts
26:01:2011 11:02:55
26:01:2011 11:01:40
21:01:2011 16:51:09
21:01:2011 16:49:54
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

澄清数字排序:宇宙飞船运营商&lt; =&gt;强制对其两个操作数进行数值解释。因此,每个包含日期和时间的字符串$ a和$ b被解释为它们是数字。要执行此操作,此示例中的perl将提取日期并在第一个':'处停止。这就是为什么时间,甚至月份和年份都被完全忽略的原因,我们只按降序排序当月的那一天。

最后,如果你真的想反向排序日期,那么时间和需要保持格式你可以使用这段代码:

> perl -e '@a = <>; sub dmyt2ymdt { my $dmyt=shift; $ymdt=join(q(), (split(/[:\s]+/,$dmyt))[2,1,0,3,4,5])}   print sort { dmyt2ymdt($b) <=> dmyt2ymdt($a) } @a' ts
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37
26:01:2011 11:02:55
26:01:2011 11:01:40
21:01:2011 16:51:09
21:01:2011 16:49:54

这是一个更好的格式化版本(我没有测试):

sub dmyt2ymdt {
  my $dmyt = shift;
  my ($day, $mon, $year, $h, $m, $s) = split(/[:\s]+/, $dmyt);
  return join('', $year, $mon, $day, $h, $m, $s);
}

此排序功能

sort { dmyt2ymdt($b) <=> dmyt2ymdt($a) }

然后调用上面的帮助器。在您的示例中,我们在列表中有8个条目进行排序,并且函数被调用24次。所以它没有性能效率。但是对于最多可能有几百甚至几千个条目的小型列表,对您来说可能没问题。 如果你有大型列表,你应该只进行一次格式转换,但它仍然需要内存。因此,对于大型列表,您需要权衡内存与执行时间,通常就是这种情况。

如果性能是优化标准,您可以像评论一样动态进行转换,并在其他答案和评论中显示:

sort { $b <=> $a }  map { dmyt2ymdt($_) } @a

..对于我上面的例子。现在,每个元素只进行一次转换。不过,我们必须在内存中保留一个临时列表。我不确定perl如何优化上述结构。有人可能会认为以下内容更容易优化:

reverse sort map { dmyt2ymdt($_) } @a

也可以用于测试集。排序默认返回字符串比较,这与相同长度的字符串的数字比较相同,在其他字符串有数字的位置不使用空格。

希望这有帮助!

答案 2 :(得分:2)

Jon Skeet's答案更好! (如果可以,只需将时间戳更改为ISO 8601 format。)

但是如果你不能改变格式,你可以这样做:

#!/usr/bin/perl -w
use strict;

my %h;

while(<DATA>) {
    chomp;
    $h{$_}++;
}

sub iso_8601 {
    $_ = shift;
    if (/(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)/) {
        return "$3:$2:$1:$4:$5:$6";
    }    
}

foreach my $key (sort {iso_8601($a) cmp iso_8601($b)} keys %h) { 
    print "$key -- $h{$key}\n";
}

__DATA__
21:01:2011 16:51:09
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

(重复的时间戳我假设你有自己的逻辑来处理。通过散列它们,重复计算,我只是打印他们的计数...)

结果:

21:01:2011 16:49:54 -- 1
21:01:2011 16:51:09 -- 1
26:01:2011 11:01:40 -- 1
26:01:2011 11:02:55 -- 1
05:04:2011 11:48:37 -- 2
05:04:2011 11:51:13 -- 2

修改

好的,如果您担心效率,(sort {iso_8601($a) cmp iso_8601($b)} keys %h)不是最佳,因为每个哈希元素多次调用iso_8601()函数。

对于“Schwartzian Transform”形式,您可以执行以下操作:

print join("\n",
    map { $_->[0].' -- '.$h{$_->[0]} }
    sort { $a->[1] cmp $b->[1] }
    map {[$_,iso_8601($_)]} 
        keys %h);

这将产生与上面相同的输出。那么你每个哈希键只调用iso_8601()一次,而不是多次......

解剖(从右到左,从下到上):

keys %h                         # list of all the keys of the hash
map {[$_,iso_8601($_)]}         # create anon array with 2 elements:
                                # original stamp and ISO 8601 stamp
sort { $a->[1] cmp $b->[1] }    # list sorted on the ISO 8601 stamp
map { $_->[0].' -- '.$h{$_->[0]} }  # a list of strings with original stamp
                                    # and hash count
join("\n",                      # join the list into a string with a "\n"

编辑2

我很难理解你想要的东西。试试这个:

#!/usr/bin/perl -w
use strict;

my %h;
my $i=0;

while(<DATA>) {
    chomp;
    $h{$_}++;
}

sub iso_8601 {
    $_ = shift;
    if (/(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)$/) {
        $i++;
        return "$3-$2-$1 $4:$5:$6";
    }    
}

foreach my $key (sort {iso_8601($b) cmp iso_8601($a)} keys %h) { 
    print iso_8601($key).":\t\t"."$key -- $h{$key}\n";
}

print "\n";

输出:

YYYY-MM-DD HH:MM:SS                 your record... 
2011-09-01 10:48:18:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200943  01:09:2011 10:48:18 -- 1
2011-09-01 10:48:18:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200943  01:09:2011 10:48:18 -- 1
2011-08-25 10:20:16:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200944  25:08:2011 10:20:16 -- 1
2011-08-25 10:20:16:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200944  25:08:2011 10:20:16 -- 1
2011-08-25 10:19:05:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200945  25:08:2011 10:19:05 -- 1
2011-08-25 10:19:05:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200945  25:08:2011 10:19:05 -- 1
2011-08-25 10:17:26:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200946  25:08:2011 10:17:26 -- 1
2011-08-25 10:17:26:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200946  25:08:2011 10:17:26 -- 1
2011-07-01 16:13:55:        WGA_PD7124a WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192654  01:07:2011 16:13:55 -- 1
2011-07-01 16:11:23:        WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192655  01:07:2011 16:11:23 -- 1
2011-07-01 11:04:26:        WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Male(Unknown)   192656  01:07:2011 11:04:26 -- 1
2011-05-04 17:35:52:        WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184558  04:05:2011 17:35:52 -- 1
2011-05-04 17:35:52:        WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184558  04:05:2011 17:35:52 -- 1
2011-05-04 17:34:27:        WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184557  04:05:2011 17:34:27 -- 1
2011-05-04 17:34:27:        WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184557  04:05:2011 17:34:27 -- 1
2011-03-23 10:03:23:        PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179502  23:03:2011 10:03:23 -- 1
2011-03-23 10:02:30:        PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179470  23:03:2011 10:02:30 -- 1
2011-02-15 09:24:31:        3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174878  15:02:2011 09:24:31 -- 1
2011-02-15 09:21:19:        3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174970  15:02:2011 09:21:19 -- 1
2011-02-15 09:16:32:        3074    3074    87(10)  87(10)  87      100.00  109     Female(Unknown) 174860  15:02:2011 09:16:32 -- 1
2011-02-09 09:54:48:        CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173382  09:02:2011 09:54:48 -- 1
2011-02-09 09:54:48:        3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173382  09:02:2011 09:54:48 -- 1
2011-02-09 09:51:02:        3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173284  09:02:2011 09:51:02 -- 1
2011-02-09 09:51:02:        CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173284  09:02:2011 09:51:02 -- 1

这是你在想什么?它解析行尾的时间戳,并按降序对这些记录进行排序。这有什么问题?

答案 3 :(得分:0)

前段时间我遇到了同样的问题,当我按照Jon Skeet提出的方式对列表进行排序时,我解决了转换格式的问题,这是我的代码:

my @source = <DATA>;
my @data =  sort {$a<=>$b} map { m!(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)!; "$3$2$1$4$5$6";} @source;
foreach ( @data ) {
    s!(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})!$3:$2:$1 $4:$5:$6!;
    print $_, "\n";
}

__DATA__
05:04:2011 11:48:37
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
21:01:2011 16:51:09
15:04:2012 11:48:37

结果是:

21:01:2011 16:49:54
21:01:2011 16:51:09
26:01:2011 11:01:40
26:01:2011 11:02:55
05:04:2011 11:48:37
05:04:2011 11:48:37
05:04:2011 11:51:13
05:04:2011 11:51:13
15:04:2012 11:48:37

答案 4 :(得分:0)

首先,了解您要做的事情。接下来,让它工作。然后,如有必要,优化。

轻松比较时间戳的一种方法是将它们转换为时代的偏移量。您可以使用Time::Local。鉴于您没有获得任意值,而是定义明确的时间戳,您可以进行一些过早的优化,并使用_nochecktimelocaltimegm

以下是使用您提供的示例数据执行此操作的一种方法:

#!/usr/bin/env perl

use strict; use warnings;

use Time::Local 'timelocal';

my @data;

while (my $line = <DATA>) {
    last unless $line =~ /\S/;
    chomp $line;
    push @data, [ split ' ', $line ];
}

@data = sort compare_records_descending_time @data;

print join("\t", @$_), "\n" for @data;

sub compare_records_descending_time {
    return ts2time($b) <=> ts2time($a);
}

sub ts2time {
    my ($record) = @_;
    my $ts = "@{ $record }[-2, -1]";

    # timestamp is day:mon:year hr:min:sec
    # timelocal expects arguments in sec, min, hr, day, mon, year

    return timelocal(($ts =~ /([0-9]+)/g)[5, 4, 3, 0, 1, 2]);
}

__DATA__
124a WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192654  01:07:2011 16:13:55
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192655  01:07:2011 16:11:23
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Male(Unknown)   192656  01:07:2011 11:04:26
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184557  04:05:2011 17:34:27
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184557  04:05:2011 17:34:27
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174878  15:02:2011 09:24:31
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174970  15:02:2011 09:21:19
3074    3074    87(10)  87(10)  87      100.00  109     Female(Unknown) 174860  15:02:2011 09:16:32
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173382  09:02:2011 09:54:48
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173284  09:02:2011 09:51:02
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173382  09:02:2011 09:54:48
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173284  09:02:2011 09:51:02
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200946  25:08:2011 10:17:26
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200946  25:08:2011 10:17:26
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179502  23:03:2011 10:03:23
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179470  23:03:2011 10:02:30