my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");
my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");
什麼是Perl中最快的方式mylist2插入是在mylist1,而不是已經在mylist2(ABCDE)的所有元素。
my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");
my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");
什麼是Perl中最快的方式mylist2插入是在mylist1,而不是已經在mylist2(ABCDE)的所有元素。
my %k;
map { $k{$_} = 1 } @mylist1;
map { $k{$_} = 1 } @mylist2;
@mylist2 = keys %k;
或者:
my %k;
map { $k{$_} = 1 } @mylist2;
push(@mylist2, grep { !exists $k{$_} } @mylist1);
其實 - 因爲他們沒有考慮是否在任原名單可能存在重複這些可能是錯的。
在您的問題中,您沒有說清楚列表是否應表示集合(不能包含重複項)或僅僅是普通列表。你有效地想要@mylist2 = @mylist1 U @mylist2
表明你正在將它們當作集合來對待。
編輯:改變增量分配 - 保存散列值的讀
[原來的答覆爲2008-11-27下調至「由於這個問題」;從那裏的分析是新的截至2008-11-29。]
最快 - 不確定。這工作,但它並不漂亮:
#!/bin/perl -w
use strict;
my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");
my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");
sub value_in
{
my($value, @array) = @_;
foreach my $element (@array)
{
return 1 if $value eq $element;
}
return 0;
}
@mylist2 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1);
print sort @mylist2, "\n";
這避免了轉換數組到哈希 - 但對於大型陣列,該value_in
子可能會很慢。
由於問題是「什麼是最快的方法」,我做了一些基準測試。對我來說不是太大的驚喜,我的方法是最慢的。有些令我驚訝的是,最快速的方法並非來自List :: MoreUtils。以下是測試代碼和結果 - 使用我原始提案的修改版本。
#!/bin/perl -w
use strict;
use List::MoreUtils qw(uniq);
use Benchmark::Timer;
my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");
my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");
sub value_in
{
my($value) = shift @_;
return grep { $value eq $_ } @_;
}
my @mylist3;
my @mylist4;
my @mylist5;
my @mylist6;
my $t = Benchmark::Timer->new(skip=>1);
my $iterations = 10000;
for my $i (1..$iterations)
{
$t->start('JLv2');
@mylist3 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1);
$t->stop('JLv2');
}
print $t->report('JLv2');
for my $i (1..$iterations)
{
$t->start('LMU');
@mylist4 = uniq(@mylist1, @mylist2);
$t->stop('LMU');
}
print $t->report('LMU');
for my $i (1..$iterations)
{
@mylist5 = @mylist2;
$t->start('HV1');
my %k;
map { $k{$_} = 1 } @mylist5;
push(@mylist5, grep { !exists $k{$_} } @mylist1);
$t->stop('HV1');
}
print $t->report('HV1');
for my $i (1..$iterations)
{
$t->start('HV2');
my %k;
map { $k{$_} = 1 } @mylist1;
map { $k{$_} = 1 } @mylist2;
@mylist6 = keys %k;
$t->stop('HV2');
}
print $t->report('HV2');
print sort(@mylist3), "\n";
print sort(@mylist4), "\n";
print sort(@mylist5), "\n";
print sort(@mylist6), "\n";
Black JL: perl xxx.pl
9999 trials of JLv2 (1.298s total), 129us/trial
9999 trials of LMU (968.176ms total), 96us/trial
9999 trials of HV1 (516.799ms total), 51us/trial
9999 trials of HV2 (768.073ms total), 76us/trial
ABCDE
ABCDE
ABCDE
ABCDE
Black JL:
這是Perl的5.10.0對古董的Sun E450編譯爲32位SPARC與多重運行Solaris 10
我相信,測試裝置是公平的;它們都將它們的答案生成爲一個新的數組,與mylist1和mylist2分開(因此mylist1和mylist2可以重新用於下一個測試)。指定爲HV1(散列值1)的答案在分配給@ mylist5後有定時開始,我認爲這是正確的。然而,當我與分配前的開始時間,但仍然最快:
Black JL: perl xxx.pl
9999 trials of JLv2 (1.293s total), 129us/trial
9999 trials of LMU (938.504ms total), 93us/trial
9999 trials of HV1 (505.998ms total), 50us/trial
9999 trials of HV2 (756.722ms total), 75us/trial
ABCDE
ABCDE
ABCDE
ABCDE
9999 trials of HV1A (655.582ms total), 65us/trial
Black JL:
因爲你的「(ABCDE)」的評論,我假設你實際上意味着推到在mylist2 mylist1這些元素不在mylist1中。如果這個假設是不正確的,那麼你需要說一下你想要的東西的順序。
首先,存儲哪些元素在mylist1中的一個散列中,然後將mylist2中所有那些未在散列中找到的元素推到mylist1。
my %in_mylist1;
@in_mylist1{@mylist1} =();
push @mylist1, grep ! exists $in_mylist1{$_}, @mylist2;
你可以只使用List::MoreUtils
模塊的uniq
:
use List::MoreUtils qw(uniq);
my @mylist1;
push(@mylist1, "A");
push(@mylist1, "B");
push(@mylist1, "C");
my @mylist2;
push(@mylist2, "A");
push(@mylist2, "D");
push(@mylist2, "E");
@mylist2 = uniq(@mylist1, @mylist2);
printf "%s\n", (join ',', @mylist2); # A,B,C,D,E
好的,這將工作,但它不是學習Perl的方法... – Alnitak 2008-11-27 20:44:32
my(%work);
@work{@mylist1, @mylist2} = undef;
@mylist2 = sort keys %work;
這是正常的,如果你不需要保留原來的順序。 – 2008-11-29 16:49:16
根據我的測量,第二個選項是最快的 - 並且比List :: MoreUtils中的uniq方法快。 – 2008-11-30 07:04:52