2011-02-03 11 views
16

cuando intento el siguiente¿Cómo restar una matriz de una matriz?

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 

print Dumper [grep {not @bl} @a]; 

puedo obtener una matriz vacía. Hubiera esperado que @bl se restara de @a, por lo que la salida fue yellow purple pink.

¿Qué pasa aquí?

+2

“sustraer” no es la correcta palabra aquí Cuando ** encuentres ** la palabra correcta, descubrirás que es una que desencadena un ataque hash Pavloviano. – tchrist

Respuesta

33

lo necesario para convertir @bl en un hash para realizar la diferencia de conjuntos:

my %in_bl = map {$_ => 1} @bl; 
my @diff = grep {not $in_bl{$_}} @a; 
+7

Esto es mejor que la respuesta de preguntas frecuentes para esta pregunta: el faq solo muestra cómo calcular la "diferencia simétrica" ​​entre dos matrices – mob

+1

@mob: así que envíe un correo electrónico a brian con una actualización sugerida. – tchrist

+6

En Perl 5.10 o posterior, podría escribir 'my @diff = grep {not $ _ ~~ @bl} @a;' –

4

Ver perlfaq4: How do I compute the difference of two arrays?

En su código, not es, probablemente, no hacer lo que piensa que está haciendo.

not @bl siempre habrá 1 si @bl es una matriz vacía, y si undef@bl no está vacío. No significa "elementos que no están en @bl" en ningún sentido.

4

@b1 se evalúa como verdadera (que es una matriz con un no-cero número de elementos), por lo que la prueba booleana en su grep constructo (not @b1) siempre devolverá falso. grep filtra una matriz que devuelve solo los elementos para los cuales la prueba booleana devuelve verdadero.

Debe probar para ver si $_ (el elemento de la matriz actualmente bajo consideración) está en @bl o no. Una forma de hacer esto es generar un hash temporal utilizando @bl como las claves, a continuación, en su cheque comunicado grep la presencia de $_ en las claves hash:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 

# create a hash 
my %h; 

# nifty trick - use a hash slice to populate the 
# hash. The values are irrelevant so we'll use @bl 
# for those too 
@h{@bl} = @bl; 

print Dumper [grep {!exists $h{$_}} @a]; 
+1

Poblando los valores de '% h' es overkill. Si usa 'exists', poblar con' @h {@bl} =() 'estará bien y probablemente sea más rápido. –

1

Otra forma, usando la función minus del Acme::Tools módulo CPAN:

use strict; 
use warnings; 
use Data::Dumper; 
use Acme::Tools qw(minus); 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 
my @diff = minus(\@a, \@bl); 
print Dumper(\@diff); 

__END__ 

$VAR1 = [ 
      'yellow', 
      'purple', 
      'pink' 
     ]; 
2

Otra opción usando perl5i:

use perl5i::2; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 
my @diff = @a->diff(\@bl); 

say @diff->mo->perl; 
4

Desde Perl 5.18.0 el operador de Smartmatch se considera experimental: The smartmatch family of features are now experimental. Por eso, ya no usaría esta solución más abajo.

Otra manera con el SmartMatch-operador (si tiene perl- versión 5.010 o superior):

#!/usr/bin/env perl 
use warnings; 
use 5.012; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 

my @s = grep{ not $_ ~~ @bl } @a; 
say "@s"; # yellow purple pink 
+0

¿No resultará esto en el rendimiento 'O (n^2)', ya que el operador de Smartmatch coincide con cada elemento de '@ bl' para cada elemento en' @ a'? – Floegipoky

+0

@Floegipoky: Tu comentario me parece razonable. Con Perl 5 dejé de usar el operador de Smartmatch. He editado la respuesta. –

-1

Otra forma es utilizar:

List::Compare CPAN module 
use List::Compare ; 
... 
my $compare_obj 
    = List::Compare->new(\@a , \@b1) ; 
@diff = $compare_obj->get_Lonly() ; 
... 
Cuestiones relacionadas