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



我必须按降序排序我的哈希键,这是一个时间戳(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

您可以将格式更改为yyyy:mm:dd hh24:mi:ss吗?在这一点上,你会有一个自然的排序。基本上,将所有内容按重要性降序排列会对机器更友好:)

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

从你的问题来看,我不清楚你真正想要如何排序以及你如何生成示例。在您期望的排序顺序示例中,我无法检测到任何顺序。一个可能的解决方案是在底部。

让我澄清一下:

给定一个文本文件"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

澄清数值排序:太空船操作符<=>强制对其两个操作数进行数值解释。因此字符串$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

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

希望这对你有帮助!

Jon Skeet的答案更好!(也就是说,只要改变你的时间戳,如果你可以,为ISO 8601格式。)

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

#!/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()函数在每个哈希元素中被调用多次。

对于"史瓦兹变换"的一种形式,你可以这样做:

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 h1> 很难理解你想要什么。试试这个:
#!/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).":tt"."$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

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

我在前一段时间遇到了同样的问题,当我按照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

首先,了解您要做什么。接下来,让它工作。然后,如有必要,进行优化。

比较时间戳的一种方法是将它们转换为纪元的偏移量。您可以使用Time::Local。考虑到您得到的不是任意值,而是定义良好的时间戳,您可以进行一些过早的优化,并使用timelocaltimegm_nocheck版本。

下面是使用您提供的示例数据的一种方法:
#!/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

相关内容

最新更新