按日期在ASCII上对PERL数组进行排序

cap*_*ser 1 arrays sorting perl

我需要做的是编写一个脚本,它将读入目录列表然后对它们进行排序,最后一个目录将被"关闭".

我的$ last_one = pop @sorted;

然后将删除最后一个目录 - 使用系统("rm- rf $ last_one")或remove_tree($ last_one).

 1  #!/usr/bin/perl
 2  use strict;
 3  use warnings;
 4
 5  my $dir_to_process = "/production/log/fo/archive/";
 6  opendir DH, $dir_to_process or die "Sorry, this is not going to work out $!";
 7
 8  while (my $name = readdir DH) {
 9       next if $name =~ /^\./;
10       push(my @unsorted,$name) ;
11       my @sorted_dir = sort @unsorted;
12       foreach my $sorted (@sorted_dir) {
13       print "$sorted\n";
14       sleep 1 ;
15       }
16
17  }
Run Code Online (Sandbox Code Playgroud)

但是我在排序目录时遇到了很多麻烦 - 它们是用这种格式编写的.这是实际输出.

2013Nov12
2013Sep14
2013Jul15
2013Jan20
2013Sep11
2013May31
2013Jul04
2012Dec09
2013Oct12
2013Oct09
2012Dec27
2013Nov28
2013Mar24
2013Jun06
2013Jun25
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 5

让我们假设存在一个convert_date将日期转换为YYYYMMDD格式的函数.如果你有一个,那么简单的字符串比较会找到最旧的.

my ($oldest) =
   sort { convert_date($a) cmp convert_date($b) }
   @dirs;
Run Code Online (Sandbox Code Playgroud)

快点:

my ($oldest) =
   map $_->[0],
   sort { $a->[1] cmp $b->[1] }
   map [ $_, convert_date($_) ],
   @dirs;
Run Code Online (Sandbox Code Playgroud)

最快的:

my ($oldest) =
   map substr($_, 8),
   sort
   map convert_date($_) . $_,
   @dirs;
Run Code Online (Sandbox Code Playgroud)

但排序(O(N log N))是找到一个元素(O(N))的浪费方式.

my $oldest = $dirs[0];
for (@dirs) {
   $oldest = $_ if convert_date($_) lt $oldest;
}
Run Code Online (Sandbox Code Playgroud)

快点?

use List::Util qw( minstr );
my $oldest = substr(minstr( map { convert_date($_) . $_ } @dirs ), 8);
Run Code Online (Sandbox Code Playgroud)

现在,剩下的就是写作了convert_date.

use Carp qw( croak );

my %month_num_by_en_name = (
   Jan => 1,  Feb =>  2,  Mar =>  3,  Apr =>  4,
   May => 5,  Jun =>  6,  Jul =>  7,  Aug =>  8,
   Sep => 9,  Oct => 10,  Nov => 11,  Dec => 12,
);


sub convert_date {
   my ($date) = @_;

   my ($y,$m,$d) = $date =~ m/^(\d{4})(\w{3})(\d{2})\z/
      or croak("Invalid input");

   $m = $month_num_by_en_name{$m}
      or croak("Invalid input");

   return sprintf("%04d%02d%02d", $y,$m,$d);
}
Run Code Online (Sandbox Code Playgroud)

您还可以使用DateTime :: Format :: Strptime.这样可以更轻松地支持其他语言.

use DateTime::Format::Strptime qw( );

my $format = DateTime::Format::Strptime->new(
   pattern  => '%Y%b%d',
   locale   => 'en_US',
   on_error => 'croak',
);

sub convert_date {
   my ($date) = @_;
   return $format->parse_datetime($date)->strftime('%Y%m%d');
}
Run Code Online (Sandbox Code Playgroud)

  • 通常最好在库代码中使用`croak` /`carp`而不是`die` /`warn`.因为您的用户(我指的是使用您的库的程序员)并不关心代码中的错误所在.他关心用无效参数调用函数的位置. (2认同)