2008-11-27 8 views

Répondre

12
my %k; 
map { $k{$_} = 1 } @mylist1; 
map { $k{$_} = 1 } @mylist2; 
@mylist2 = keys %k; 

Autre possibilité:

my %k; 
map { $k{$_} = 1 } @mylist2; 
push(@mylist2, grep { !exists $k{$_} } @mylist1); 

En fait - ce peut-être tort parce qu'ils ne tiennent pas compte si les doublons peuvent exister dans l'une des listes originales.

Vous n'avez pas dit dans votre question si les listes sont censées représenter des ensembles (qui ne peuvent contenir de doublons) ou simplement des listes simples. Que vous voulez effectivement @mylist2 = @mylist1 U @mylist2 suggère que vous les traitez comme des ensembles.

EDIT: incrément changé pour attribuer - enregistre une lecture de la valeur de hachage

+0

Ceci est correct si vous n'avez pas besoin de garder l'ordre d'origine. –

+1

La deuxième option est la plus rapide selon mes mesures - et plus rapide que la méthode uniq dans List :: MoreUtils. –

2

[réponse originale au 2008-11-27 à « Puisque la question »; l'analyse à partir de là est nouvelle à compter du 2008-11-29.]

Le plus rapide - pas sûr. Cela fonctionne, bien que ce n'est pas assez:

#!/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"; 

Cela évite la conversion des tableaux en hash - mais pour les grands tableaux, le sous value_in peut être lent. Puisque la question était «Quelle est la méthode la plus rapide?», J'ai fait quelques analyses comparatives. Pour ma surprise non-trop-vaste, ma méthode était la plus lente. Un peu à ma grande surprise, la méthode la plus rapide n'était pas de List :: MoreUtils. Voici le code de test et les résultats - en utilisant une version modifiée de ma proposition originale.

#!/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: 

C'est Perl 5.10.0 compilé pour SPARC 32 bits avec multiplicité sur un ancien Sun Solaris 10. E450 exécutant

Je crois que les configurations de test sont justes; ils génèrent tous leur réponse dans un nouveau tableau, séparé de mylist1 et mylist2 (ainsi mylist1 et mylist2 peuvent être réutilisés pour le test suivant). La réponse désignée par HV1 (valeurs de hachage 1) a le début de la temporisation après l'affectation à @ mylist5, ce que je pense être correct. Cependant, quand je l'ai fait le moment avec le début avant l'affectation, il était encore plus rapide:

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

En raison de votre « (ABCDE) » commentaire, je suppose que vous pousser signifiait réellement sur maliste1 ces éléments mylist2 qui ne sont pas dans mylist1. Si cette hypothèse est incorrecte, vous devez indiquer dans quel ordre vous souhaitez que les choses se terminent.

D'abord, stockez les éléments dans mylist1 dans un hachage, puis insérez tous les éléments dans mylist2 non trouvés dans le hachage. mylist1.

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

Vous pouvez simplement utiliser le uniq du module de List::MoreUtils:

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

ok, ça marchera, mais c'est pas moyen d'apprendre Perl ... – Alnitak

+3

Apprendre à identifier et à utiliser des modules est une partie assez importante de l'apprentissage perl. – oeuftete

+0

Bien sûr, mais vous devez toujours connaître les principes de base – Alnitak

0
my(%work); 
@work{@mylist1, @mylist2} = undef; 
@mylist2 = sort keys %work; 
+0

Si les doublons sont autorisés dans mylist2 (et je ne vois pas pourquoi ils ne le seraient pas), alors cette solution les supprime. – noswonky

Questions connexes