在Perl中如何对日期进行排序?

8
我该如何在Perl中对日期进行排序?
my @dates =  ( "02/11/2009" , "20/12/2001" , "21/11/2010" ); 

我有一个包含以上日期的数组。如何对这些日期进行排序?
我的日期格式为dd/mm/YYYY

12
将日期存储为“YYYY/MM/DD”更加方便。在展示日期时,您可以自由进行任何操作,而不必担心日期格式的问题。 - Sinan Ünür
4个回答

19
@dates = sort { join('', (split '/', $a)[2,1,0]) cmp join('', (split '/', $b)[2,1,0]) } @dates;

或者使用单独的排序子程序:

sub mysort {
    join('', (split '/', $a)[2,1,0]) cmp join('', (split '/', $b)[2,1,0]);
}
@dates = sort mysort @dates;

更新:更高效的方法是使用Schwartzian Transform:

@dates = 
    map $_->[0],
    sort { $a->[1] cmp $b->[1] }
    map  [ $_, join('', (split '/', $_)[2,1,0]) ], @dates;

4
使用Schwartzian Transform或其他缓存键排序方法来做这件事,这样您就不必每次都重新计算值。 - brian d foy
@brian:谢谢,我忘记了这个 :-) - Eugene Yarmash
如果你的日期带有时间,例如29/4/2021-00:10:10,你可以使用[/-]分割。然后使用 [2,1,0,3] 进行字段连接,即:sort { join('', (split '[\/\-]', $a)[2,1,0,3]) cmp join('', (split '[\/\-]', $b)[2,1,0,3]) } - gaoithe

4

基于这个原因,我更喜欢YYYY/MM/DD的日期格式。它可以确保在1000/01/019999/12/31之间正确排序。

my @sorted_alt = sort map { join '/', reverse split '/', $_  } @dates;

如果你真的需要以 DD/MM/YYYY 格式显示日期,你可以尝试使用完整的Schwartzian transform
my @sorted = map {
  join '/', reverse split '/', $_
}
sort
map {
  join '/', reverse split '/', $_ 
} @dates;

或者

my @sorted = map {
  join '/', reverse @$_
}
sort { "@$a" cmp "@$b" }
map {
  [ reverse split '/', $_ ]
} @dates;

1

这里有很多人正确地认为日期的原始格式应该是yyyy-mm-dd格式,但是还没有人给出可以处理这种情况的Perl代码。所以在这里提供一下:

my @dates = (
    '2014-08-15',
    '2016-09-13',
    '2001-01-02',
    '1998-09-22',
    '1998-09-21',
    '1998-09-23',
    '1999-04-20',
    '2020-01-30',
);

@dates = sort {$a cmp $b} @dates;   # 1998 is the first date's year
@dates = sort {$b cmp $a} @dates;   # 2014 is the first date's year

Brad Gilbert的回答包含了这种情况的代码。只需要@dates = sort @dates; - melpomene
啊,说得好 -- 但我喜欢我的例子,因为它实际上可以在一个正确值的数组上工作(没有分割映射魔法),它展示了升序与降序的两种顺序,并且不会不必要地插入排序后的值。 - HoldOffHunger

1

或者使用时间戳的纪元格式并将它们作为数字进行排序。然后按照您想要的输出格式转换日期字符串。这样,您就不必被原始字符串的格式束缚住。


2
能否提供一个示例,这样会更有帮助。 - slm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接