[Respuesta original a partir de 2008-11-27 hasta "Dado que la pregunta"; el análisis de allí en adelante es nuevo a partir de 2008-11-29.]
Lo más rápido - no estoy seguro. Esto funciona, aunque no es bastante:
#!/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";
Esto evita la conversión de las matrices en los hashes - pero para las grandes matrices, la sub value_in
puede ser lento.
Como la pregunta era "¿cuál es el método más rápido?", Realicé algunas evaluaciones comparativas. Para mi sorpresa no demasiado vasta, mi método fue más lento. Para mi sorpresa, el método más rápido no fue de List :: MoreUtils. Aquí está el código de prueba y los resultados, usando una versión modificada de mi propuesta original.
#!/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:
Esta es Perl 5.10.0 compilado para SPARC de 32 bits con multiplicidad en un antiguo E450 Sun con Solaris 10.
Creo que las configuraciones de prueba son justos; todos ellos generan su respuesta en una nueva matriz, separada de mylist1 y mylist2 (por lo que mylist1 y mylist2 pueden reutilizarse para la próxima prueba). La respuesta designada HV1 (valores de hash 1) tiene el inicio de temporización después de la asignación a @ mylist5, que creo que es correcta. Sin embargo, cuando hice la sincronización con el inicio antes de la asignación, que era todavía más rápida:
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:
Esto está bien si no es necesario para mantener el orden original. –
La segunda opción es la más rápida según mis mediciones, y más rápida que el método uniq en List :: MoreUtils. –