我必须按时间戳(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
答案 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"
我很难理解你想要的东西。试试这个:
#!/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。鉴于您没有获得任意值,而是定义明确的时间戳,您可以进行一些过早的优化,并使用_nocheck
版timelocal
或timegm
。
以下是使用您提供的示例数据执行此操作的一种方法:
#!/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