perl arrays comparison

¿Cómo puedo verificar si una matriz de Perl contiene un valor particular?



arrays comparison (11)

Estoy tratando de encontrar una manera de verificar la existencia de un valor en una matriz sin iterar a través de la matriz.

Estoy leyendo un archivo para un parámetro. Tengo una larga lista de parámetros con los que no quiero lidiar. @badparams estos parámetros no deseados en una matriz @badparams .

Quiero leer un nuevo parámetro y, si no existe en @badparams , procesarlo. Si existe en @badparams , vaya a la siguiente lectura.


Método 1: grep (puede tener cuidado mientras se espera que el valor sea una expresión regular).

Trate de evitar el uso de grep , si mira a los recursos.

if ( grep( /^$value$/, @badparams ) ) { print "found"; }

Método 2: Búsqueda lineal

for (@badparams) { if ($_ eq $value) { print "found"; } }

Método 3: utilizar un hash

my %hash = map {$_ => 1} @badparams; print "found" if (exists $hash{$value});

Método 4: smartmatch

(agregado en Perl 5.10, marcado es experimental en Perl 5.18).

use experimental ''smartmatch''; # for perl 5.18 print "found" if ($value ~~ @badparams);

Método 5: Usar la List::MoreUtils módulos principales List::MoreUtils

use List::MoreUtils qw(any uniq);; @badparams = (1,2,3); $value = 1; print "found" if any {$_ eq $value} @badparams;


@files es una matriz existente

my @new_values = grep(/^2[/d].[/d][A-za-z]?/,@files); print join("/n", @new_values); print "/n";

/^2[/d◆.[/d◆[A-za-z◆?/ = vaues a partir de 2 aquí puede poner cualquier expresión regular


Aunque es conveniente de usar, parece que la solución de conversión a hash cuesta bastante rendimiento, lo que fue un problema para mí.

#!/usr/bin/perl use Benchmark; my @list; for (1..10_000) { push @list, $_; } timethese(10000, { ''grep'' => sub { if ( grep(/^5000$/o, @list) ) { # code } }, ''hash'' => sub { my %params = map { $_ => 1 } @list; if ( exists($params{5000}) ) { # code } }, });

Salida de prueba de referencia:

Benchmark: timing 10000 iterations of grep, hash... grep: 8 wallclock secs ( 7.95 usr + 0.00 sys = 7.95 CPU) @ 1257.86/s (n=10000) hash: 50 wallclock secs (49.68 usr + 0.01 sys = 49.69 CPU) @ 201.25/s (n=10000)


Ciertamente quieres un hash aquí. Coloque los parámetros incorrectos como claves en el hash, luego decida si un parámetro en particular existe en el hash.

our %bad_params = map { $_ => 1 } qw(badparam1 badparam2 badparam3) if ($bad_params{$new_param}) { print "That is a bad parameter/n"; }

Si está realmente interesado en hacerlo con una matriz, consulte List::Util o List::MoreUtils


Mejor propósito general: especialmente matrices cortas (1000 elementos o menos) y codificadores que no están seguros de qué optimizaciones se adaptan mejor a sus necesidades.

# $value can be any regex. be safe if ( grep( /^$value$/, @array ) ) { print "found it"; }

Se ha mencionado que grep pasa por todos los valores, incluso si el primer valor de la matriz coincide. Esto es cierto, sin embargo, grep sigue siendo extremadamente rápido para la mayoría de los casos . Si estás hablando de matrices cortas (menos de 1000 elementos), la mayoría de los algoritmos serán bastante rápidos de todos modos. Si está hablando de arrays muy largos (1,000,000 elementos) grep es aceptablemente rápido sin importar si el elemento es el primero o el medio o el último en el arreglo.

Casos de optimización para arrays más largos:

Si su matriz está ordenada , use una "búsqueda binaria".

Si se busca repetidamente la misma matriz muchas veces, primero cópiela en un hash y luego verifique el hash. Si la memoria es una preocupación, entonces mueva cada elemento de la matriz al hash. Más memoria eficiente pero destruye la matriz original.

Si se buscan repetidamente los mismos valores dentro de la matriz, cree perezosamente un caché. (a medida que se busca en cada elemento, primero verifique si el resultado de la búsqueda se almacenó en un hash persistente. Si el resultado de la búsqueda no se encuentra en el hash, luego busque la matriz y coloque el resultado en el hash persistente para que la próxima vez Encuéntralo en el hash y omite la búsqueda).

Nota: estas optimizaciones solo serán más rápidas cuando se trate de arrays largos. No sobre optimices.


Puede usar la función smartmatch en Perl 5.10 de la siguiente manera:

Para la búsqueda de valor literal, hacer lo siguiente hará el truco.

if ( "value" ~~ @array )

Para la búsqueda escalar, hacer lo siguiente funcionará como antes.

if ($val ~~ @array)

Para la matriz en línea haciendo a continuación, funcionará como se indica arriba.

if ( $var ~~ [''bar'', ''value'', ''foo''] )

En Perl 5.18, smartmatch está marcado como experimental, por lo tanto, debe desactivar las advertencias activando el pragma experimental agregando a continuación su script / módulo:

use experimental ''smartmatch'';

Alternativamente, si desea evitar el uso de smartmatch, entonces, como dijo Aaron, use:

if ( grep( /^$value$/, @array ) ) { #TODO: }


Simplemente convierte el array en un hash:

my %params = map { $_ => 1 } @badparams; if(exists($params{$someparam})) { ... }

También puede agregar más parámetros (únicos) a la lista:

$params{$newparam} = 1;

Y luego recuperar una lista de parámetros (únicos) de vuelta:

@badparams = keys %params;


hay dos maneras de hacer esto. Puede usar la tirada de los valores en un hash para una tabla de búsqueda, como lo sugieren las otras publicaciones. (Voy a añadir sólo otro idioma).

my %bad_param_lookup; @bad_param_lookup{ @bad_params } = ( 1 ) x @bad_params;

Pero si se trata de datos en su mayoría de caracteres de palabras y no de muchos metadatos, puede volcarlos en una alternancia de expresiones regulares:

use English qw<$LIST_SEPARATOR>; my $regex_str = do { local $LIST_SEPARATOR = ''|''; "(?:@bad_params)"; }; # $front_delim and $back_delim being any characters that come before and after. my $regex = qr/$front_delim$regex_str$back_delim/;

Esta solución debería ajustarse para los tipos de "valores incorrectos" que está buscando. Y, de nuevo, podría ser totalmente inapropiado para ciertos tipos de cuerdas, por lo que debe tener cuidado con Emptor .


Esta publicación del blog analiza las mejores respuestas a esta pregunta.

Como breve resumen, si puede instalar módulos CPAN, las soluciones más legibles son:

any(@ingredients) eq ''flour'';

o

@ingredients->contains(''flour'');

Sin embargo, un idioma más común es:

any { $_ eq ''flour'' } @ingredients

¡Pero por favor no uses la first() función first() ! No expresa la intención de su código en absoluto. No utilice el operador ~~ "Smart Match": está roto. Y no use grep() ni la solución con un hash: recorren toda la lista.

any() se detendrá tan pronto como encuentre su valor.

Echa un vistazo a la publicación del blog para más detalles.


El punto de referencia de @ eakssjo está roto: mide la creación de hashes en bucle y la creación de expresiones regulares en bucle. Versión fija (más he agregado List::Util::first y List::MoreUtils::any ):

use List::Util qw(first); use List::MoreUtils qw(any); use Benchmark; my @list = ( 1..10_000 ); my $hit = 5_000; my $hit_regex = qr/^$hit$/; # precompute regex my %params; $params{$_} = 1 for @list; # precompute hash timethese( 100_000, { ''any'' => sub { die unless ( any { $hit_regex } @list ); }, ''first'' => sub { die unless ( first { $hit_regex } @list ); }, ''grep'' => sub { die unless ( grep { $hit_regex } @list ); }, ''hash'' => sub { die unless ( $params{$hit} ); }, });

Y el resultado (es para 100_000 iteraciones, diez veces más que en la respuesta de @ eakssjo):

Benchmark: timing 100000 iterations of any, first, grep, hash... any: 0 wallclock secs ( 0.67 usr + 0.00 sys = 0.67 CPU) @ 149253.73/s (n=100000) first: 1 wallclock secs ( 0.63 usr + 0.01 sys = 0.64 CPU) @ 156250.00/s (n=100000) grep: 42 wallclock secs (41.95 usr + 0.08 sys = 42.03 CPU) @ 2379.25/s (n=100000) hash: 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) @ 10000000.00/s (n=100000) (warning: too few iterations for a reliable count)


my @badparams = (1,2,5,7,''a'',''zzz''); my $badparams = join(''|'',@badparams); # ''|'' or any other character not present in params foreach my $par (4,5,6,7,''a'',''z'',''zzz'') { if ($badparams =~ //b$par/b/) { print "$par is present/n"; } else { print "$par is not present/n"; } }

Es posible que desee comprobar la coherencia de los espacios iniciales numéricos