[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:
Ceci est correct si vous n'avez pas besoin de garder l'ordre d'origine. –
La deuxième option est la plus rapide selon mes mesures - et plus rapide que la méthode uniq dans List :: MoreUtils. –