2009-06-16 15 views
42

Tengo un script Perl que cuenta el número de ocurrencias de varias cadenas en un archivo de texto. Quiero poder verificar si una cierta cadena aún no es una clave en el hash. ¿Hay una mejor manera de hacer esto por completo?¿Cómo puedo ver si un hash Perl ya tiene una determinada clave?

Aquí es lo que estoy haciendo:

foreach $line (@lines){ 
    if(($line =~ m|my regex|)) 
    { 
     $string = $1; 
     if ($string is not a key in %strings) # "strings" is an associative array 
     { 
      $strings{$string} = 1; 
     } 
     else 
     { 
      $n = ($strings{$string}); 
      $strings{$string} = $n +1; 
     } 
    } 
} 
+4

La pregunta es, ¿por qué te molestas con eso? Si no existe, entonces $ n será undef. El valor numérico de Undef es 0, entonces $ n + 1 = 1. No hay necesidad de verificar si existe en el hash para comenzar. –

Respuesta

95

creo para comprobar si existe una clave en un hash que acaba de hacer

if (exists $strings{$string}) { 
    ... 
} else { 
    ... 
} 
+13

Tenga en cuenta que perl autovigilará cualquier tecla intermedia que no exista en un hash multidimensional para "verificar" si existe la clave que busca en el último hash. No es un problema con un hash simple como este ejemplo pero ... my% test =(); print "bar" if (existe $ test {'foo'} {'bar'}); # perl acaba de autovivificar la tecla foo para buscar la barra print "foo existe ahora y es posible que no haya esperado eso". if (existe $ test {'foo'}); – Drew

6

supongo que este código debe responder a su pregunta:

use strict; 
use warnings; 

my @keys = qw/one two three two/; 
my %hash; 
for my $key (@keys) 
{ 
    $hash{$key}++; 
} 

for my $key (keys %hash) 
{ 
    print "$key: ", $hash{$key}, "\n"; 
} 

salida:

three: 1 
one: 1 
two: 2 

La iteración se puede simplificar a:

$hash{$_}++ for (@keys); 

(Ver $_ en perlvar.) E incluso se puede escribir algo como esto:

$hash{$_}++ or print "Found new value: $_.\n" for (@keys); 

cual reporta cada tecla la primera vez que es encontró.

+0

Sí, la cosa es que no sabré por adelantado cuáles serán las llaves. –

+1

Sí, no necesita verificar la presencia de la clave para este propósito. Simplemente puede decir $ strings {$ 1} ++. Si la clave no está allí, se agregará undef como valor, que ++ interpretará como 0 para usted. – Arkadiy

+0

Claro. El punto es que puede reemplazar todo el cuerpo de su ciclo (bajo if) con $ strings {$ 1} ++. – zoul

-1

Sólo puede ir con:

if(!$strings{$string}) .... 
+0

Sí, eso también funciona. ¡Gracias! –

+7

Esto solo funciona si todas las claves tienen valores que no son falsos. En general, esa es una mala suposición. Use exists(), que está especialmente diseñado solo para esto. –

+2

@brian de foy - Ah, ja. Sabía que no debería haber respondido :-) –

9

Bueno, todo el código puede limitarse a:

foreach $line (@lines){ 
     $strings{$1}++ if $line =~ m|my regex|; 
} 

Si el valor no está ahí, ++ operador asuma que ser 0 (y luego incremente a 1). Si ya está allí, simplemente se incrementará.

+0

Si bien su respuesta es cierta, responde la pregunta sobre hash. – Chris

9

Recomendaría no usar if ($hash{$key}) ya que no hará lo que espera si la clave existe pero su valor es cero o está vacío.

+1

Esas circunstancias determinadas son solo para claves anidadas. Para este problema, existe es la respuesta. No usar existe para claves anidadas en una sola toma. –

+1

Downvote sigue siendo un poco duro, la advertencia no queda invalidada por la simplicidad del script en esta pregunta. El punto más importante es el problema de usar if ($ hash {$ key}) sin definir ni existir: el problema "cero pero verdadero". – RET

+0

La cosa "cero pero verdadero" merece un voto popular. Pero lo que dijiste sobre autovigilancia es simplemente incorrecto y merece un voto negativo. – innaM

Cuestiones relacionadas