代码之家  ›  专栏  ›  技术社区  ›  Zaid

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

  •  2
  • Zaid  · 技术社区  · 15 年前

    我有一个存储在哈希中的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 回复  |  直到 15 年前
        1
  •  7
  •   larelogio    15 年前

    如果格式为10个字符:

    sort { substr($a,3,2) cmp substr($b,3,2) } @dates;
    
        2
  •  12
  •   friedo    15 年前

    你可以用 Schwartzian Transform ,像这样:

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

    这需要 %data 并将其放入一个匿名数组中,其中第一个元素是键,第二个元素是拆分后的中间字段。 / . 然后它按数组的第二个元素排序,并使用另一个元素 map 以获取密钥的原始列表。

        3
  •  7
  •   jrockway    15 年前

    解析和排序:

    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;
    
        4
  •  2
  •   brian d foy    15 年前

    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;=>,是数值比较运算符。

    如果您有一个复杂的函数需要拉出您想要排序的部分,那么不要在排序函数内部进行排序。首先将它拉出,因为同一个元素可以多次调用排序块。下面是一个例子,说明如何在每个项目的第一个数字后提取第一个单词,然后不敏感地对这些单词进行排序。

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

    也可以这样写,使用一个被称为施瓦兹变换的技巧:

    @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中有关哈希排序的问题。