我有一个包含文件列表的数组。我想以一种方式对它进行排序,它会让我在数组的开头和之后的其余文件中包含.txt文件。
这就是我现在正在做的事情,它运作良好。
@files = (grep(/\.txt$/,@files),grep(!/\.txt$/,@files));
有没有更好的方法呢?
答案 0 :(得分:10)
您询问了有关为多个文件扩展名执行此操作的后续评论。在那种情况下,我将建立Schwartzian变换。如果您是ST的新手,我推荐Joseph Hall在 Effective Perl Programming 中的解释。尽管Second Edition很快就会出现,但我们基本上保留了他的解释,因此first edition同样出色。谷歌图书似乎只显示第一版每页的一英寸,所以你在那里运气不好。
在这个答案中,我使用加权函数来决定哪些扩展应该移到顶部。如果扩展没有明确的权重,我只是用词典方式对它进行排序。您可以使用sort来获取您想要的订单:
@files = qw(
buster.pdf
mimi.xls
roscoe.doc
buster.txt
mimi.txt
roscoe.txt
buster.rpm
mimi.rpm
);
my %weights = qw(
txt 10
rpm 9
);
my @sorted =
map { $_->{name} }
sort {
$b->{weight} <=> $a->{weight}
||
$a->{ext} cmp $b->{ext}
||
$a cmp $b
}
map {
my( $ext ) = /\.([^.]+)\z/;
{ # anonymous hash constructor
name => $_,
ext => $ext,
weight => $weights{$ext} || 0,
}
}
@files;
$" = "\n";
print "@sorted\n";
答案 1 :(得分:5)
my @sorted =
(
sort( grep /\.txt\z/, @files ),
sort( grep ! /\.txt\z/, @files )
);
这里的技巧是你要对列表进行分区,然后独立地对每个分区进行排序。根据您的操作,这可能比尝试在一个排序操作中执行所有操作要好得多。相反,它可能并不总是更好。
有许多其他方法可以完成这项工作,但它们并非如此简单。 :)
这是我的MacBook Air与vanilla Perl 5.10.1的快速基准:
There are 600 files to sort
brian: 3 wallclock secs @ 369.75/s (n=1161)
control: 3 wallclock secs @ 1811.99/s (n=5744)
leon: 4 wallclock secs @ 146.98/s (n=463)
mobrule: 3 wallclock secs @ 101.57/s (n=324)
sort: 4 wallclock secs @ 559.62/s (n=1746)
这是脚本:
use Benchmark;
use vars qw(@files);
@files = qw(
buster.pdf
mimi.xls
roscoe.doc
buster.txt
mimi.txt
roscoe.txt
) x 100;
printf "There are %d files to sort\n", scalar @files;
sub leon {
my @sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, !/\.txt$/ ]
} @files;
}
sub brian {
my @sorted =
(
sort( grep /\.txt\z/, @files ),
sort( grep ! /\.txt\z/, @files )
);
}
sub mobrule {
my @sorted =
sort { ($b=~/\.txt\z/) <=> ($a=~/\.txt\z/) || $a cmp $b }
@files;
}
sub plain_sort {
my @sorted = sort @files;
}
sub control {
my @sorted = @files;
}
timethese( -3,
{
brian => \&brian,
leon => \&leon,
mobrule => \&mobrule,
control => \&control,
sort => \&plain_sort,
}
);
答案 2 :(得分:5)
@sorted = sort { $b=~/\.txt$/ <=> $a=~/\.txt$/ || $a cmp $b } @files
首先放置.txt文件,然后按字母顺序排序(按字母顺序排列)。
@sorted = sort { $b=~/\.txt$/ <=> $a=~/\.txt$/ } @files
将首先放置.txt文件,否则保留原始订单(sort
稳定,因为Perl 5.8)
答案 3 :(得分:4)
Sort将可选块作为第一个参数,但在这种情况下,Schwartzian变换会更快。
@files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, !/\.txt$/ ] } @files;
答案 4 :(得分:3)
要有效地处理多个扩展,您可以通过在一次传递中对数组进行分区来修改brian d foy的已排序grep
,然后单独对每个分区进行排序。
use strict;
use warnings;
use List::MoreUtils qw(part);
my @files = qw(
bar Bar.pm bar.txt
bar.jpeg foo foo.pm
foo.jpeg zebra.txt zebra.pm
foo.bat foo.c foo.pl
Foo.pm foo.png foo.tt
orange apple zebra.stripe
);
my @parts = part { get_extension_priority($_) } @files;
my @sorted = map { sort( @{ $_ || [] } ) } @parts;
print map "$_\n", @sorted;
BEGIN {
# Set extension priority order
my @priority = qw( stripe txt nomatch pl jpeg );
# make a hash to look up priority by extension
my %p = map { $priority[$_], $_ } 0..$#priority;
sub get_extension_priority {
my $file = shift;
return scalar @priority
unless /[.](\w*)$/;
return scalar @priority
unless exists $p{$1};
return $p{$1};
}
}
答案 5 :(得分:1)
代码高尔夫? 这不会产生令人讨厌的警告:
@files = map { $_->[0] } sort { @$b <=> @$a } map { [$_, /\.txt$/] } @files