我有一个存储在哈希中的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.
我怎样才能做到这一点?
答案 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中关于排序哈希的问题。