perl对日期时间字符串的多个arryrefs进行排序
我想对arrayref%results(时间字符串,从旧到新)进行排序,它有多个键,但我只发布了一个键来显示它的外观:perl对日期时间字符串的多个arryrefs进行排序,perl,sorting,arrayref,Perl,Sorting,Arrayref,我想对arrayref%results(时间字符串,从旧到新)进行排序,它有多个键,但我只发布了一个键来显示它的外观: 'Ende Monatswechsel P-Konten' => [ '17.02.2018 05:17:39', '14.02.2018 04:28:11',
'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[$\u,sort{$a$b}@{$results{$\u}],key%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;
}
}
类似这样的方法会奏效:
#!/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;
更新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;
拆分字符串并比较部分适用于对多种类型的“多部分”值进行排序,但是,由于您处理的是日期时间,因此可以使用核心模块Time::Piece
将字符串转换为可以使用
操作符进行比较的日期时间对象
Time::Piece
提供了strtime
方法,该方法使用格式字符串将日期字符串解析为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')
}
使用v5.10;
严格使用
使用警告;
使用时间::件;
我的@VAL=(
'17.02.2018 05:17:39',
'14.02.2018 04:28:11',
'23.02.2018 03:17:17',
'22.02.2018 03:39:20',
);
表示排序{dt($a)dt($b)}@vals;
###
次级dt{
我的$str=班次;
返回时间::工件->strTime($str,'%e.%m.%Y%H:%m:%S')
}
我现在实际上使用了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=();
my@array;
我的@sorted;
我的%a是f\n;
对于我的$key(key%结果){
对于我的$i(0..$#{$results{$key}}){
推送@array,$results{$key}[$i];
}
@排序{
我的@a=split/[\.]/,$a;
my@b=split/[\.]/,$b;
返回(
$a[2]$b[2]或
$a[1]$b[1]或
$a[0]$b[0]或
$a[3]cmp$b[3]
);
}@数组;
$aref_n{$key}=[@sorted];
@数组=();
}定义“它不起作用”的含义;它怎么不起作用?你得到了什么样的输出?你期望得到什么样的输出?我期望:
'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', ]
通常的方法是拆分字符串并比较各个部分。更好的方法是强制上游系统将日期输出为YYYY-mm-dd HH:mm:SS
。然后您可以使用字符串比较。@Unsal:好的,现在我完全糊涂了。您最初的帖子强烈暗示您想要对存储在中的数组进行排序散列。这就是我的代码所做的。现在您已经发布了在散列中构建数组的代码(并且,据我所见,以正确的顺序构建它)。所以,我真的不知道你在问什么。@Dave:很抱歉没有把它弄得足够精确。是的,这是一个arrayref,你看到的只是输出的一部分。乍一看,它看起来已经排序了,但我有>100个值,其中日期在该arrayref中未排序。嗨,Dave,谢谢你的回答。我不确定schwart是如何排序的zian转换应该在这里工作,因为我有固定长度的日期字符串。顺便说一句,您的建议不起作用,它返回:$VAR1=['17.02.2018 05:17:39','23.02.2018 03:17:17','14.02.2018 04:28:11','22.02.2018 03:39:20'];
@Unsal:看起来你不是在运行我的实际代码。我的代码返回一个数组,但你正在转储一个数组引用。@Unsal:我的代码将数组引用($data
)作为输入并返回一个数组(@sorted
)。编辑您的问题以添加代码的当前状态,我来看看。在我的代码中,我将时间戳推入哈希(%results),如下所示:push@{$results{$action},$timestamp;
但我不能将您的代码与我的arrayref一起使用。如果它真的只是几个元素,这是很好的,但对于任何更长的列表,我建议实际使用Schwartzian变换,因为Time::Piece
并没有那么便宜。它仍然会很贵,但要少得多。公平点说来,我个人会我会选择简洁易读而不是优化,除非速度至关重要。我同意。我只是想指出,Time::Piece
有点贵。(这让我很惊讶;有一次我不得不放弃它,转而手动解析,因为它增加了太多的开销。但那段代码需要处理很多。)我也很惊讶,因为它是一个核心模块,我假设它是一个快速的C实现,但感谢您的洞察力。然后,施瓦茨变换的一个特点是效率(因为在短路之前只比较它需要什么)抱歉,我可能没有说清楚:我发现模块太慢(对于耗时代码中的长列表),没有转换;没有排序,只是time::Piece
花费的时间比我预期的要长。(因此,我在这里提到了转换,因为排序TP->strtime
对每个比较都运行一次;转换对每个列表元素运行一次,然后缓存的对象仅用于比较。)
$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'
]
};
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')
}
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=();