2010-10-29 12 views
7

Soy un perdedor novato. Tengo un código en el que una variable se carga con varios valores durante un ciclo foreach. Lo que quiero hacer es realizar alguna operación en esa variable solo si está en esa matriz. ¿Cuál es la más eficiente manera de hacer esto en Perl ya que los datos en los que estoy trabajando son muy grandes.Perl: encuentre si el valor de una variable coincide con el de una matriz

Un ejemplo sencillo de mi pregunta es, decir que tengo una gran variedad de frutas Quiero

@fruits_i_like = qw (mango banana apple); 

Pero tengo una variable $ fruta en un bucle foreach que recibe el nombre de las frutas desde un archivo de datos que tiene todos los diferentes tipos de frutas ¿Cómo elegiría solo aquellos casos de fruta $ que están en mi matriz de @fruits_i_like?

+1

¿Qué tan grande es 'grande'? – Zaid

+0

y el archivo que necesito leer es de aproximadamente 50 MB. – sfactor

+0

@sfactor: Eso no es tan malo entonces. – Zaid

Respuesta

10

Puede utilizar un hash de la siguiente manera:

my %h = map {$_ => 1 } @fruits_i_like; 
if (exists $h{$this_fruit}) { 
    # do stuff 
} 

Aquí es un punto de referencia que compara esta manera vs solución mfontani

#!/usr/bin/perl 
use warnings; 
use strict; 
use Benchmark qw(:all); 

my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
my %h = map {$_ => 1 } @fruits_i_like; 
my $count = -3; 
my $r = cmpthese($count, { 
    'grep' => sub { 
     if (scalar grep $this_fruit eq $_, @fruits_i_like) { 
      # do stuff 
     } 
    }, 
    'hash' => sub { 
     if (exists $h{$this_fruit}) { 
      # do stuff 
     } 
    }, 
}); 

Salida:

  Rate grep hash 
grep 1074911/s -- -76% 
hash 4392945/s 309% -- 
+1

Cambia el 'sub {}' a 'q {}' y ejecuta ese benchmark de nuevo. La sobrecarga de llamada de la subrutina puede cambiar demasiado los números. – tchrist

+3

Si crea% h solo para este propósito, ¿no debería formar parte del índice de referencia? –

+3

@ Øyvind Skaar: No lo creo, porque OP quiere combinar frutas muchas veces. % h se crea solo una vez y se usa muchas veces.Es diferente de la solución grep donde se realiza el grep para cada fruta diferente. – Toto

11

Perl 5.10 o superior?

use strict; 
use warnings; 
use 5.10.0; 
my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
if ($this_fruit ~~ \@fruits_i_like) { 
    say "yummy, I like $this_fruit!"; 
} 

Antes de 5.10:

use strict; 
use warnings; 
my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
if (scalar grep $this_fruit eq $_, @fruits_i_like) { 
    print "yummy, I like $this_fruit!\n"; 
} 

La desventaja es que el conjunto matriz se analiza a través de encontrar coincidencias. Puede que esta no sea la mejor opción, en cuyo caso puede usar List::MoreUtils 'any(), que devuelve verdadero una vez que coincide con un valor y no continúa pasando por la matriz.

use strict; 
use warnings; 
use List::MoreUtils qw/any/; 
my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
if (any { $this_fruit eq $_ } @fruits_i_like) { 
    print "yummy, I like $this_fruit!\n"; 
} 

¡Feliz hacking!

9

Esto es efectivamente un problema de búsqueda. Sería más rápido buscar los valores de @fruits_i_like en un hash como %fruits_i_like (que es O (1) frente a O (n) de una matriz).

Convertir la matriz a un hash utilizando la siguiente operación:

open my $data, '<', 'someBigDataFile.dat' or die "Unable to open file: $!"; 

my %wantedFruits; 
@wantedFruits{@fruits_i_like} =(); # All fruits_i_like entries are now keys 

while (my $fruit = <$data>) {  # Iterates over data file line-by-line 

    next unless exists $wantedFruits{$fruit}; # Go to next entry unless wanted 

    # ... code will reach this point only if you have your wanted fruit 
} 
Cuestiones relacionadas