2011-01-26 14 views
14

Supongamos que tengo una serie de números y quiero asegurar que todos estos caen dentro de uno de los conjuntos (x, y, z), actualmente estoy comprobando que las siguientes evalúa a 0:¿Hay un operador perl "no en"?

scalar (grep { $_ ne x && $_ ne y && $_ ne z } @arr) 

simplemente preguntaba si no va a ser más fácil si tuviéramos "IN" y los operadores "no en" SQL-como en perl también ..

scalar (grep { $_ NOT IN (x,y,z) } @arr) 

O hay uno ya ??

Gracias, Trinity

Respuesta

14

Una forma típica de resolver esto es utilizar un hash:

my %set = map {$_ => 1} qw(x y z); # add x, y and z to the hash as keys 
            # each with a value of 1 

my @not_in_set = grep {not $set{$_}} @arr; 
2
use List::Member; 
my $target = 'bar'; 
my @look_in = ('foo','baz','bar','etc'); 

if(member($target, @look_in) + 1) { 
print "It's a member of the array\n"; 
} 

que puede hacer el truco

+0

Esa es una biblioteca práctica, gracias :) – trinity

15

Las bibliotecas List::Util o List::MoreUtils son muy útil aquí para probar la membresía de la lista donde a usted no le importan los valores en sí, sino simplemente la existencia. Estos son más eficientes que grep, porque dejan de recorrer la lista tan pronto como se encuentra una coincidencia, lo que realmente puede acelerar las cosas con listas largas. Además, estos módulos están escritos en C/XS, que es más rápido que cualquier implementación pura-perl.

use List::MoreUtils 'any'; 

my @list = qw(foo bar baz); 

my $exists = any { $_ eq 'foo' } @list; 
print 'foo ', ($exists ? 'is' : 'is not'), " a member of the list\n"; 

$exists = any { $_ eq 'blah' } @list; 
print 'blah ', ($exists ? 'is' : 'is not'), " a member of the list\n"; 

(Si usted está restringido a sólo el uso de módulos que vienen con núcleo de Perl, puede utilizar first en la lista :: Util - primero envía con Perl en 5.7.3.)

+0

Hola, gracias, esto parece ser una buena alternativa! – trinity

+0

IMO esta debería ser la respuesta elegida – andrefs

11

Si está usando Perl 5.10 o superior (o está dispuesto a usar una función experimental en Perl 5.18 y posteriores), el operador de Smart Match hará exactamente lo que está buscando.

# if Perl 5.18 or higher; otherwise not needed 
no warnings 'experimental::smartmatch'; 

my @filter = qw(X Y Z); 
my $not_in_filter = scalar grep { ! ($_ ~~ @filter) } @array; 

Si el filtro y/o @array son grandes, puede ser lento, sin embargo, debido a que es O (N^2). En ese caso, todavía se puede utilizar la concordancia inteligente, y sólo cambiar el filtro:

my %filter = map { $_ => 1 } qw(X Y Z); 
my $not_in_filter = scalar grep { ! ($_ ~~ %filter) } @array; 

Ver Smart Matching in Detail en perldoc perlsyn para obtener más información.

Además, si necesita admitir versiones de perl entre 5.10 y 5.18, considere utilizar el módulo de cpan experimental. Esto hace verificaciones de versión e incluye el 'no advertencias' si encuentra una versión de Perl que lo requiera.

use experimental 'smartmatch'; 

Ver: https://search.cpan.org/~leont/experimental-0.016/lib/experimental.pm

+0

Gracias @Robert, ~~ es algo nuevo para mí !! – trinity

+3

@trinity Y lamentablemente la familia de características Smartmatch se marcó como experimental en Perl 5.18.0, por lo que probablemente no debería comenzar a usarlo. –

4

Si hay menos de unos pocos millones de cosas diferentes en la matriz, podría también utilizan el método libro de texto de la diferencia de conjuntos utilizando un hash:

my %seen; 
@seen{ @arr } =(); # Create a key for every distinct value in @arr 
delete @seen{ qw(x y z) }; # And remove the ones for x, y, and z 

if (keys %seen) { 
    # There was something in @arr that's not x, y, or z 
} else { 
    # There wasn't 
} 
+0

Wow @hobbs, enfoque bastante diferente, gracias :) – trinity

3
my $target = 'bar'; 
my @look_in = ('foo','baz','bar','etc'); 
if($target ~~ @look_in) { 
    print "target is in array "; 
} 

~~ está en la matriz

my $target = 'bar'; 
my @look_in = ('foo','baz','bar','etc'); 
if(not $target ~~ @look_in) { 
    print "target is not in array"; 
} 

esto se llama Smartmatch, algunas personas recomiendan no usarlas, pero el trabajo funciona bastante bien con la lista de cadenas.

Cuestiones relacionadas