2016-11-29 2 views
1

Ниже мой код:Как отсортировать дату в порядке возрастания с помощью Perl?

@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"; 

Ожидаемый результат должен быть дата в порядке возрастания.

+1

Пожалуйста, проверьте ответы и проголосуйте, если вы согласны с тем же ...! – ssr1012

ответ

0

Попробуйте выполнить следующую тривиальную функцию сортировки.
ВНИМАНИЕ: Это ведет никаких данных проверки формата вообще

sub sortByDate{ 
    my @a = split(/\//,$a); 
    my @b = split(/\//,$b); 
    return $a[2]<=>$b[2] || $a[0]<=>$b[0] || $a[1]<=>$b[1]; 
} 
0

вы смотрели на доступные даты манипуляции модули? Я уверен, что есть некоторые, которые сделают большую часть работы для вас ...

В любом случае ответ на ваш код выше: ваш сортир имеет много проблем; код даже не работает на Perl 5.20:

  1. Косые черты не экранированы, но они являются разделителями рисунков. Я использовал m## - Исключения зафиксированы в OP тоже.
  2. Вы не переупорядочиваете компоненты даты. Все дело в том, чтобы сократить первый год; где вы думаете, что вы это делаете? I sprintf() 'дата в фиксированном YYYYMMDD номер.
  3. Вы только назначая первый элемент из матчей в $adate и $bdate, т.е. сортировочного только месяц - исправляются sprintf()
  4. Вы соответствуете фиксированным строкам в финиковых компонентах, но день/месяц в вашем примере имеет либо один или двух символов. Вместо этого я использовал \d{1,2}.

Вот неподвижная суб:

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; 
} 

Там до сих пор нет проверки ошибок, поэтому работает со строгим предупреждением/возвратит много ошибок, если вы передадите неверные данные. Вам не нужен дополнительный код, если вы проверяете формат первого, но, чтобы предотвратить ошибки из плохо сформированных дат вы можете также добавить некоторые проверки и использование строки КСС запасной вариант:

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; 
} 
4

Вы собирались для:

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 
} 

Если вы переставить дату в виде yyyymmdd, вы могли бы просто использовать лексикографический род.

Я считаю, что это самое быстрое решение:

my @sorted_events = 
    map { substr($_, 8) } 
    sort 
    map { sprintf('%3$04d%1$02d%2$02d%4$s', split(qr{/}, $_), $_) } 
    @events; 
+1

Удивительный ответ. – ssr1012

-1

Там может быть несколько подходов к sort дат с использованием Perl. Я подытожил два подхода в сценарии.


Оба подхода используют Schwartzian transform, чтобы отсортировать его.

  1. Просто используйте split, а затем отсортируйте его по годам, месяцам и дням. Используйте его, если вы уверены в формате ввода.
  2. Использование Time::Piece для разбора в Time::Piece объект, а затем сортировать его. Используйте его, если вы не уверены в формате ввода и нуждаетесь в проверке перед обработкой.

Вы можете использовать любого из них в зависимости от ваших предпочтений.

#!/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; 
2

Преобразовать в 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; 

Примечание - в приведенном выше, если strptime не удается, она остается в исходной строке. Это вызовет предупреждение в sort, потому что вы больше не сортируете число.

Смежные вопросы