我有一個包含文件列表的數組。我想對它進行排序,讓它在數組的開頭和文件的其餘部分都有.txt文件。如何對數組進行排序,以便某些文件擴展名排在最前面?
這就是我現在正在做的,它工作正常。
@files = (grep(/\.txt$/,@files),grep(!/\.txt$/,@files));
有沒有更好的方法來做到這一點呢?
我有一個包含文件列表的數組。我想對它進行排序,讓它在數組的開頭和文件的其餘部分都有.txt文件。如何對數組進行排序,以便某些文件擴展名排在最前面?
這就是我現在正在做的,它工作正常。
@files = (grep(/\.txt$/,@files),grep(!/\.txt$/,@files));
有沒有更好的方法來做到這一點呢?
Sort將可選塊作爲第一個參數,儘管在這種情況下Schwartzian變換會更快。
@files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, !/\.txt$/ ] } @files;
在我的測試中,我發現Schwartzian變換稍慢(但只是一點點)。在我的回答中,我必須在陣列上做兩遍,但在你的例子中,你也是。你也必須提供參考。 – 2010-03-26 17:54:00
我第一次聽說Schwartzian變換。這絕對有趣。假設我首先需要txt文件,然後是rpm,然後是其他文件。上面的代碼如何改變?我不確定我明白它究竟在做什麼。 – rarbox 2010-03-26 18:08:44
@rarbox:參見http://stackoverflow.com/questions/594257/when-are-schwartzian-transforms-useful – Ether 2010-03-26 18:13:05
my @sorted =
(
sort(grep /\.txt\z/, @files),
sort(grep ! /\.txt\z/, @files)
);
這裏的技巧是,你是分區列表,然後獨立分揀每個分區。根據你在做什麼,這可能比嘗試在一個排序操作中做所有事情要好得多。相反,它可能並不總是更好。
有很多其他的方式來完成這件事,但他們不是這麼簡單。 :)
這裏有一個快速的基準上我的MacBook Air與香草的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,
}
);
在所有這些中,我認爲這可能是最清潔和最明顯的。 – 2010-03-26 18:08:56
根據他的後續評論想要分類更多文件擴展名,這可能不是正確的答案。 – 2010-03-26 18:15:04
@sorted = sort { $b=~/\.txt$/ <=> $a=~/\.txt$/ || $a cmp $b } @files
會放。 txt文件,並按照字典順序排列(按字母順序排列)。
@sorted = sort { $b=~/\.txt$/ <=> $a=~/\.txt$/ } @files
會先將.txt文件否則保留原來的順序(sort
是因爲Perl 5.8 穩定)
代碼高爾夫? 這不會產生討厭的警告:
@files = map { $_->[0] } sort { @$b <=> @$a } map { [$_, /\.txt$/] } @files
Nah,我不玩Code Golf。我正在用Net :: FTPSSL編寫一個FTP客戶端,遇到了需要按特定順序下載文件的情況,我想知道是否有更好的方法來處理,而不是我已經做的。謝謝回答。 – rarbox 2010-03-26 18:11:31
我幾乎可以肯定@ $ b應該是錯的,但我不能讓這個例子不起作用。在我看來,@ $ b應該被強制爲一個數字,而不是比較數組中的某些東西,但我想這不會發生。它爲什麼有效? – 2010-03-26 18:41:58
@brian d foy - 如果/\.txt$/匹配,則給出1,並且對數組的引用將包含類似['foo.txt',1];如果沒有,/..txt /產生空的列表,這反過來給像['foo.bin']這樣的數組引用。正如你所看到的,匹配結果的數組將包含2個元素,否則 - 1個元素。而且,是的,你是對的,在排序的塊中它被強制進入陣列中的許多元素。 – zakovyrya 2010-03-27 04:50:07
你問到這樣一個以上的文件擴展名的後續評論。在那種情況下,我會建立Schwartzian變換。如果你是ST的新手,我建議Joseph Hall的解釋在有效的Perl編程。儘管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";
高效處理多個擴展,你可以通過在一個通分割你的陣列修改布賴恩·d FOY的分類grep
s,然後排序每個獨立分區。
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};
}
}
非常好!每次我看到part()的時候,我都希望他把它命名爲partition():) – 2010-03-26 20:56:19
這是O(n),而下面的種類是O(n log n)。如果你想分區而不是排序,那麼這是一個更好的選擇。但是,如果您想分類,請在一次操作中完成所有操作。 – jrockway 2010-03-27 00:46:01