[英]How do I sort the date in ascending order using Perl?
The following is my code: 以下是我的代码:
@events=('11/17/1999', '12/6/1999', '12/23/1999',
' 1/23/2000', '1/13/2000', '2/25/2000',
'1/5/2000', '3/18/2000', '4/10/2000',
'3/12/2000', '12/31/1999');
sub sortByDate{
$adate=$a=~ /(\d{2})\/(\d{2})\/(\d{4})/;
$bdate=$b=~ /(\d{2})\/(\d{2})\/(\d{4})/;
$adate <=> $bdate;
}
@ascending = sort sortByDate @events;
print "@ascending\n";
The expected output should be the date in ascending order. 预期输出应为升序排列的日期。
You were going for: 您打算去:
sub sortByDate{
my ($am, $ad, $ay) = $a =~ /(\d{2})\/(\d{2})\/(\d{4})/;
my ($bm, $bd, $by) = $b =~ /(\d{2})\/(\d{2})\/(\d{4})/;
$ay <=> $ay || $am <=> $bm || $ad <=> $bd
}
If you were to rearrange the date into the form yyyymmdd
, you could simply use a lexicographical sort. 如果要将日期重新排列为
yyyymmdd
,则可以简单地按字典顺序使用。
I believe this is the fastest solution: 我相信这是最快的解决方案:
my @sorted_events =
map { substr($_, 8) }
sort
map { sprintf('%3$04d%1$02d%2$02d%4$s', split(qr{/}, $_), $_) }
@events;
Convert to Time::Piece
first, then sort
works exactly like you'd expect. 首先转换为
Time::Piece
,然后完全按照您的期望进行sort
。
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;
my @events=('11/17/1999', '12/6/1999', '12/23/1999',
'1/23/2000', '1/13/2000', '2/25/2000',
'1/5/2000', '3/18/2000', '4/10/2000',
'3/12/2000', '12/31/1999');
foreach my $event ( @events ) {
$event = eval { Time::Piece->strptime($event, "%m/%d/%Y" )} || $event;
}
print join "\n", sort { $a <=> $b } @events;
print "\n";
print join "\n", map { $_ -> strftime("%Y-%m-%d") } sort { $a <=> $b } @events;
Note - in the above, if strptime
fails, it stays the original string. 注意-在上面,如果
strptime
失败,它将保留原始字符串。 This will cause a warning in sort
because you're not sorting numerically any more. 这将导致
sort
警告,因为您不再对数字进行分类。
Try the following trivial sort function. 尝试以下简单的排序功能。
WARNING: It conducts no data format check whatsoever 警告:不会进行任何数据格式检查
sub sortByDate{
my @a = split(/\//,$a);
my @b = split(/\//,$b);
return $a[2]<=>$b[2] || $a[0]<=>$b[0] || $a[1]<=>$b[1];
}
Have you looked at the date manipulation modules available? 您是否看过可用的日期处理模块? I'm sure there's some that will do most of the work for you...
我敢肯定,有些可以为您完成大部分工作...
Anyway the answer to your code above: your sort sub has many issues; 无论如何,上面代码的答案是:您的sort子有很多问题; the code doesn't even run on Perl 5.20:
该代码甚至无法在Perl 5.20上运行:
m##
-- Escapes fixed in OP too. m##
-在OP中也修复了转义符。 sprintf()
'ed the date into a fixed YYYYMMDD
number. sprintf()
将日期转换成固定的YYYYMMDD
数字。 $adate
and $bdate
, ie sorting only the month -- fixed using sprintf()
$adate
和$bdate
的匹配项中的第一个元素,即仅排序月份-使用sprintf()
修复 \\d{1,2}
for those instead. \\d{1,2}
。 Here's a fixed sub: 这是一个固定的子:
sub sortByDate {
$a =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#;
my $adate = sprintf('%i%02i%02i', $3, $1, $2);
$b =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#;
my $bdate = sprintf('%i%02i%02i', $3, $1, $2);
return $adate <=> $bdate;
}
There is still no error checking, so running with strict/warning will return a lot of errors if you pass invalid data. 仍然没有错误检查,因此如果您传递无效数据,则使用严格/警告运行将返回很多错误。 You don't need the extra code if you validate the format first, but to prevent errors from badly formed dates you can also add some checking and use string cmp fallback:
如果首先验证格式,则不需要额外的代码,但是为防止格式错误的日期产生错误,您还可以添加一些检查并使用字符串cmp fallback:
sub sortByDate {
my $adate = sprintf('%i%02i%02i', $3, $1, $2)
if ($a =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#);
my $bdate = sprintf('%i%02i%02i', $3, $1, $2)
if ($b =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#);
return $adate <=> $bdate if ($adate && $bdate);
return $a cmp $b;
}
There could be multiple approaches to sort
dates using Perl. 使用Perl可能有多种方法
sort
日期进行sort
。 I have summarized two approaches in the script. 我在脚本中总结了两种方法。
Both the approach uses Schwartzian transform to sort it. 两种方法都使用Schwartzian变换对其进行排序。
Time::Piece
to parse into Time::Piece
object and then sort it. Time::Piece
解析为Time::Piece
对象,然后对其进行排序。 Use it, if you are not sure about input format and need validation before processing. You can use anyone between them based on your preferences. 您可以根据自己的喜好在他们之间使用任何人。
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;
my @events = ( '11/17/1999', '12/6/1999', '12/23/1999',
'1/23/2000', '1/13/2000', '2/25/2000',
'1/5/2000', '3/18/2000', '4/10/2000',
'3/12/2000', '12/31/1999');
my @sorted_events = map { $_ -> [0] }
sort {
# year
$a -> [1] -> [2] <=> $b -> [1] -> [2] ||
# month
$a -> [1] -> [0] <=> $b -> [1] -> [0] ||
# day
$a -> [1] -> [1] <=> $b -> [1] -> [1]
}
map { [ $_, [ split /\// ] ] }
@events;
# you can also use Time::Piece
my @sorted_events_again = map { $_ -> [1] }
sort { $a -> [0] <=> $b -> [0] }
map { [ Time::Piece -> strptime($_, "%m/%d/%Y"), $_ ] }
@events;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.