我想对arrayref%results(时间字符串,从旧到新)进行排序,它具有多个键,但我只是张贴了一个键以显示它的外观:
'Ende Monatswechsel P-Konten' => [
'17.02.2018 05:17:39',
'14.02.2018 04:28:11',
'23.02.2018 03:17:17',
'22.02.2018 03:39:20',
]
我期望:
'Ende Monatswechsel P-Konten' => [
'14.02.2018 04:28:11',
'17.02.2018 05:17:39',
'22.02.2018 03:39:20',
'23.02.2018 03:17:17',
]
有人知道该怎么做吗? 我尝试过:
my $columns = map [ $_, sort{$a <=> $b} @{ $results{$_} } ], keys %results;
但是它不起作用。 预先感谢。
我的代码如下:
while(my $line=<F>) {
#- Info: 19.02.2018 00:01:01 --- Start Tageswechsel-CoBa ---
#- Info: 27.11.2018 04:16:42 --- Ende Tageswechsel-CoBa ---
if ($line=~ /(\d\d\.\d\d\.\d\d\d\d \d\d:\d\d:\d\d) --- (.+? Tageswechsel-CoBa) -.*\s*$/)
{
($timestamp, $action) = ($1,$2);
}
if ( !defined $filter{$action}{$timestamp} ) {
push @{$results{$action}}, $timestamp;
$filter{$action}{$timestamp} = 1;
}
}
print Dumper(\%results)
输出:
'Start Tageswechsel-CoBa' => [
'17.02.2018 05:12:13',
'20.02.2018 04:23:16',
'22.02.2018 03:12:46',
'23.02.2018 03:34:28',
'27.02.2018 03:41:25',
'02.03.2018 03:32:26',
],
'Ende Tageswechsel-CoBa' => [
'17.02.2018 05:20:01',
'19.02.2018 06:01:02',
'20.02.2018 04:29:44',
'22.02.2018 03:19:04',
'23.02.2018 03:40:52',
'26.02.2018 06:01:26',
]
};
答案 0 :(得分:2)
类似的事情会起作用:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $data = [
'17.02.2018 05:17:39',
'14.02.2018 04:28:11',
'23.02.2018 03:17:17',
'22.02.2018 03:39:20',
];
my @sorted = sort {
my @a = split /[\. ]/, $a;
my @b = split /[\. ]/, $b;
return (
$a[2] <=> $b[2] or # year
$a[1] <=> $b[1] or # month
$a[0] <=> $b[0] or # day of month
$a[3] cmp $b[3] # time
);
} @$data;
say Dumper @sorted;
我将每个值分成多个块,然后将它们从最大的块排序到最小的块。请注意,因为时间是字符串,而不是数字,所以我使用cmp
而不是<=>
。
这有点低效,因为我要重新分割每个数据项几次。如果这是一个问题,那么您可以考虑使用Schwartzian变换之类的东西。
但是最好的解决方案是首先获得可排序的时间戳。如果您的日期是YYYY.MM.DD HH:MM:SS
,那么您可以进行简单的字符串排序。
更新:我的输出是
$ perl sortdate
$VAR1 = '14.02.2018 04:28:11';
$VAR2 = '17.02.2018 05:17:39';
$VAR3 = '22.02.2018 03:39:20';
$VAR4 = '23.02.2018 03:17:17';
更新2:我已经编辑了代码,使其更像您的示例。希望这会有所帮助。
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my %results = (
'Ende Monatswechsel P-Konten' => [
'17.02.2018 05:17:39',
'14.02.2018 04:28:11',
'23.02.2018 03:17:17',
'22.02.2018 03:39:20',
]
);
foreach my $k (keys %results) {
my @sorted = sort {
my @a = split /[\. ]/, $a;
my @b = split /[\. ]/, $b;
return (
$a[2] <=> $b[2] or # year
$a[1] <=> $b[1] or # month
$a[0] <=> $b[0] or # day of month
$a[3] <=> $b[3] # time
);
} @{ $results{$k} };
$results{$k} = \@sorted;
}
say Dumper \%results;
还有输出...
$VAR1 = {
'Ende Monatswechsel P-Konten' => [
'14.02.2018 04:28:11',
'17.02.2018 05:17:39',
'22.02.2018 03:39:20',
'23.02.2018 03:17:17'
]
};
答案 1 :(得分:1)
分割字符串并比较部分适合于对许多类型的“多部分”值进行排序,但是,由于要处理日期时间,因此可以使用核心模块Time::Piece
将字符串转换为日期时间对象,该对象可以使用<=>
运算符进行比较。
Time::Piece
提供了strptime
方法,该方法使用格式字符串将日期字符串解析为Time::Piece
对象。可以使用数值比较运算符比较Time::Piece
个对象。
use v5.10;
use strict
use warnings;
use Time::Piece;
my @vals = (
'17.02.2018 05:17:39',
'14.02.2018 04:28:11',
'23.02.2018 03:17:17',
'22.02.2018 03:39:20',
);
say for sort {dt($a) <=> dt($b)} @vals;
###
sub dt {
my $str = shift;
return Time::Piece->strptime($str,'%e.%m.%Y %H:%M:%S')
}
答案 2 :(得分:0)
我现在实际上使用了Dave的方法(因为我没有安装模块Time :: Piece),但略有不同,但是现在可以使用了,虽然不确定效率:
my @array;
my @sorted;
my %aref_n;
for my $key ( keys %results ) {
for my $i (0..$#{ $results{$key} }) {
push @array, $results{$key}[$i];
}
@sorted = sort {
my @a = split /[\. ]/, $a;
my @b = split /[\. ]/, $b;
return (
$a[2] <=> $b[2] or
$a[1] <=> $b[1] or
$a[0] <=> $b[0] or
$a[3] cmp $b[3]
);
} @array;
$aref_n{$key} = [ @sorted ];
@array=();
}