2010-03-24 6 views
5

Esta es la primera vez que manipulo hashes y matrices de esta manera, y está funcionando. Básicamente, para cada clave hay múltiples valores que quiero registrar y luego imprimir en la forma "clave -> valor -> valor -> val ..."¿Es esta la forma correcta de crear un hash Perl que utiliza matrices?

Mi código es el siguiente. Me sorprende que funcione, tan preocupado que funciona "por error". ¿Es esta la manera correcta de realizar esta tarea, o hay un método más eficiente o apropiado?

while ($source =~ m/(regex)/g) { #Get all key names from source 
    $listkey = $1; #Set current list key to the current regex result. 
    $list{$listkey} = ++$i unless $list{$listkey}; #Add the key to the hash unless it already exists. 
    $list{$listkey} = [] unless exists $list{$listkey}; #Add an array for the hash unless the hash already exists. 
    while ($loopcount==0) { 
      if ($ifcount==0) { 
        $listvalue=result_of_some_function_using_list_key; #Get the first list value by using the list key. 
        $ifcount++; #Increment so we only get the first list value once. 
      } else { 
        $listvalue=result_of_some_function_using_list_value; #Update the list value by using the last list value. 
      } 
      if ($listvalue) { #If the function returned a value... 
        push @{$list{$listkey}}, $listvalue; #...then add the value to the hash array for the key. 
      } else { #There are no more values and we need a new key. 
        $listkey=0; #Reset variable. 
        $listvalue=0; #Reset variable. 
        $loopcount++; #Increment loop counter to exit loop. 
      } 
    } 
$ifcount=0; #Reset count variable so the next listvalue can be generated from the new key. 
    $loopcount=0; #Reset count variable so another loop can begin for a new key. 
} 
foreach $listkey (keys %list) { #For each key in the hash. 
    print "$listkey --> "; #Print the key. 
    @values = @{$list{$listkey}}; #Reference the arrays of the hash. 
    print join ' --> ', @values; #Print the values. 
    print "\n"; #Print new line. 
} 
+7

Realmente debería estar en 'use strict; utilizar advertencias; 'modo – Zaid

+0

Ouch, que produjo una lista malvada de advertencias. Tendré que pasar por ellos. – Structure

+4

Espero que el código real no tenga tantos comentarios. –

Respuesta

2

El siguiente código hace lo mismo que su código, sin los pasos innecesarios.

while ($source =~ m/(regex)/g) { # Get all key names from source 
    $listkey = $1;   # Grab current regex result. 
    $listvalue = result_of_some_function_using_list_key; 
    while ($listvalue) { 
     push @{$list{$listkey}}, $listvalue; 
     $listvalue = result_of_some_function_using_list_value; 
    } 
    $listkey = 0;    # Reset variable. 
    $domain = 0;     # Reset variable. 
} 

Sin embargo, como otros han comentado, las variables globales deberían evitarse en la mayoría de los casos. En su lugar, la clave de lista y el valor de la lista deben tener un alcance léxico con my(), y las funciones para generar valores de lista deben tomar uno o más parámetros (dominio, clave de lista y/o valor de lista) como entrada.

Las líneas

$list{$listkey} = ++$i unless $list{$listkey}; 
$list{$listkey} = [] unless exists $list{$listkey}; 

en su código original no se necesitan, es suficiente con push @{ $list{$key} }, $value para inicializar una entrada.

+0

Gracias, tengo una mejor comprensión de dónde me equivoqué después de la breve explicación. – Structure

1

Nope! Si esto funciona, definitivamente es "por error". Pero también es obvio que este no es su código real y que agregó varios errores más al "traducirlo" a un ejemplo, por lo que es difícil juzgar exactamente cuál fue el propósito, pero al ir desde el esqueleto de su programa, parece como debería ser algo como:

my %result; 

while ($source =~ m/(regex)/g) { 
    my $key = $1; 
    my $value = mangle($key); 
    while ($value) { 
    push @{ $results{$key} }, $value; 
    $value = frob($value); 
    } 
} 

y no más. Sus intentos de inicializar el hash no están haciendo lo que cree que son (y no son necesarios), su ciclo while como está escrito no es una buena idea en absoluto, y tampoco lo son todas las variables globales.

2

El código anterior tiene muchos pasos innecesarios. Perl es un lenguaje muy expresivo, y permite que la lógica como este para ser expresado de manera muy sencilla:

# uncomment for some sample data 
# sub function {"@_" !~ /^\[{3}/ and "[@_]"} 
# my $source = 'one two three'; 

my %list; 
while ($source =~ m/(\S+)/g) { 
    my $key = $1; 
    my $value = function($key); 

    while ($value) { 
     push @{ $list{$key} }, $value; 
     $value = function($value) 
    } 
} 

for my $key (keys %list) { 
    print join(' --> ' => $key, @{$list{$key}}), "\n"; 
} 
+0

de acuerdo. En general, en Perl solo debería ver los índices de bucle (el bucle 'for ($ i = 0 ... 'C-style) o los contadores en los casos en que realmente necesita hacer algo con esos valores. Los contadores y los índices también son a menudo una buena fuente de errores difíciles de detectar – plusplus

Cuestiones relacionadas