2008-11-27 21 views

回答

12
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表明你正在將它們當作集合來對待。

編輯:改變增量分配 - 保存散列值的讀

+0

這是正常的,如果你不需要保留原來的順序。 – 2008-11-29 16:49:16

+1

根據我的測量,第二個選項是最快的 - 並且比List :: MoreUtils中的uniq方法快。 – 2008-11-30 07:04:52

2

[原來的答覆爲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: 
1

因爲你的「(ABCDE)」的評論,我假設你實際上意味着推到在mylist2 mylist1這些元素不在mylist1中。如果這個假設是不正確的,那麼你需要說一下你想要的東西的順序。

首先,存儲哪些元素在mylist1中的一個散列中,然後將mylist2中所有那些未在散列中找到的元素推到mylist1。

my %in_mylist1; 
@in_mylist1{@mylist1} =(); 
push @mylist1, grep ! exists $in_mylist1{$_}, @mylist2; 
23

你可以只使用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 
+0

好的,這將工作,但它不是學習Perl的方法... – Alnitak 2008-11-27 20:44:32

0
my(%work); 
@work{@mylist1, @mylist2} = undef; 
@mylist2 = sort keys %work; 
相關問題