如何使用Perl按月对dd / mm / yyyy格式化日期进行排序?

时间:2009-07-27 08:50:17

标签: perl date sorting

我有一个存储在哈希中的dd / mm / yyyy日期列表,我需要按月按顺序依次打印出来。这是相关的摘录。

use feature 'say';

for my $date (sort {$a cmp $b} keys %data) {
    say $date;
}

输出:

16/07/2008
16/08/2008
16/09/2008
17/07/2008
17/08/2008
17/09/2008, etc.

当我需要的是:

16/07/2008
17/07/2008
16/08/2008
17/08/2008
16/09/2008
16/09/2008, etc.

我怎样才能做到这一点?

4 个答案:

答案 0 :(得分:12)

您可以使用Schwartzian Transform执行此操作,如下所示:

for my $date( map  { $_->[0] }
              sort { $a->[1] <=> $b->[1] } 
              map  { [ $_, (split /\//, $_)[1] ] }
              keys %data ) { 
    ...

这将获取%data的每个键并将其放入一个匿名数组中,其中第一个元素是键,第二个元素是分割在/上的中间字段。然后它按数组的第二个元素排序,并使用另一个map来获取原始的键列表。

答案 1 :(得分:7)

解析并排序:

sub get_month {
    my $date = shift;
    my ($d, $m, $y) = split m{/}, $date;
    return $m;
}

sort { get_month($a) <=> get_month($b) } @dates;

我可能会使用DateTime,因为我想处理对象,而不是无意义的字符串:

my $parser = DateTime::Format::Natural->new(format => 'dd/mm/yyyy');
sort map { $parser->parse_datetime($_) } @dates;

答案 2 :(得分:7)

如果格式是一个严格的10个字符:

sort { substr($a,3,2) cmp substr($b,3,2) } @dates;

答案 3 :(得分:2)

perlfaq4回答How do I sort an array by (anything)?


为sort()提供比较函数(在perlfunc中的sort中描述):

@list = sort { $a <=> $b } @list;

默认排序函数是cmp,字符串比较,它将(1,2,10)排序为(1,10,2)。上面使用的&lt; =&gt;是数值比较运算符。

如果您需要复杂的功能来拉出要排序的部分,那么请不要在sort函数中执行此操作。首先将其拉出,因为对于同一元素,可以多次调用BLOCK排序。下面是一个示例,说明如何在每个项目的第一个数字后面拉出第一个单词,然后对这些单词不区分大小写。

@idx = ();
for (@data) {
    ($item) = /\d+\s*(\S+)/;
    push @idx, uc($item);
    }
@sorted = @data[ sort { $idx[$a] cmp $idx[$b] } 0 .. $#idx ];

也可以用这种方式编写,使用一种后来被称为Schwartzian变换的技巧:

@sorted = map  { $_->[0] }
    sort { $a->[1] cmp $b->[1] }
    map  { [ $_, uc( (/\d+\s*(\S+)/)[0]) ] } @data;

如果您需要对多个字段进行排序,以下范例很有用。

@sorted = sort {
    field1($a) <=> field1($b) ||
    field2($a) cmp field2($b) ||
    field3($a) cmp field3($b)
    } @data;

这可以方便地与上面给出的密钥的预先计算相结合。

有关此方法的更多信息,请参阅http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz中“远远超过您想知道的”集合中的排序文章。

另见perlfaq4中关于排序哈希的问题。