• Publicidad

Cambiar puntero en un array

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Cambiar puntero en un array

Notapor reLlene » 2012-09-28 09:22 @431

Antes de mostrarles el bloque de código, lo que deseo es poder recorrer el array @sequence, de manera tal que CADA vez que se cumple un bucle while(), el puntero del array se vaya moviendo y este valor se asigne a la variable $seq.

Supongamos...
1ª vez que corre el bucle -> $seq = 3
2ª vez que corre el bucle -> $seq = 5
3ª vez que corre el bucle -> $seq = 7
4ª vez que corre el bucle -> $seq = 9
5ª vez que corre el bucle -> $seq = 3
6ª vez que corre el bucle -> $seq = 5
7ª vez que corre el bucle -> $seq = 7
...

Vamos, hasta la 4ª vez que corre el bucle me vale un simple foreach pero... yo lo que quiero es que siga moviéndose el puntero dentro del array, independientemente de la longitud de la cadena ($code) :oops:

Mi código

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2.  
  3. # una cadena cualquiera, puede variar la longitud de ésta
  4. $code='123456789012345678901234567890123456789';
  5.  
  6. $length_code =length($code);
  7.  
  8. print 'La longitud del code es: ', $length_code, "\n";
  9.  
  10. # esta es una secuencia que debo usar
  11.         my @sequence = (3,5,7,9);  
  12.         my $i=0;
  13.        
  14. while($i < $length_code)
  15.         {
  16.                 if($i=='0')
  17.                 {
  18.                         my $head = substr($code,0,1);
  19.                 }else{
  20.                         for($j=1; $j <= $length_code ;$j++)
  21.                         {
  22.                
  23.                         my $tail += (substr($code,$j,1) * substr($sequence[$seq],$j,1));
  24.                         }
  25.                 }
  26.                 $i++;
  27.         }
  28.         my $total = $head + $tail;                                                                                      # sumo cabeza con cola
  29.  
  30. print $total;
  31.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


¡¡Agradecería la ayuda de cualquier compañero!!
Un saludo. :)
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Publicidad

Re: Cambiar puntero en un array

Notapor explorer » 2012-09-28 11:32 @522

Creo que la solución es usar una operación de módulo (%) para que el valor de $seq se mantenga dentro de los valores de los índices posibles de @sequence. Mira como ejemplo el último código del hilo Traducir código Ruby, línea 16.

Hay varios errores en el programa:

El my() de la línea 18 hace que la variable $head solo sea conocida dentro del contexto donde ha sido declarada, así que en la línea 28, Perl no sabe de dónde sale la variable $head.

Si usases 'use strict;' y 'use warnings;' en el programa, Perl te avisaría de estos fallos.

En la línea 23 ocurre lo mismo: estás declarando una variable $tail que será destruida en la línea siguiente. Recuerda que my() declara variables locales al contexto en donde están, y el contexto, en este caso, son las llaves del if().

Además, estás definiéndola con el operador '+=', con lo que estás diciendo que debe tomar el valor anterior de $tail para realizar la suma. Es un fallo, porque no existe el valor anterior de $tail.

Me gustaría saber, en concreto, cuál es el problema que intentas resolver.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Cambiar puntero en un array

Notapor reLlene » 2012-09-29 18:14 @801

Gracias explorer por las correcciones. Ahora que lo pienso, no recuerdo si fue ESA la versión que probé en el terminal. Por cierto, tampoco entiendo qué haces en la línea 16 con el uso del % pero he solventado mi problema colocando un rústico if, pero vamos, no creo que se la mejor solución, ¡ja,ja!

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. # cuando el indice del array @sequence es 4, que pase luego automáticamente a valer 0 para volver a recorrer los indices 0,1,2,3 y 4 nuevamente, las veces que sea necesario...
  2. if($seq==4){
  3. $seq=0;
  4. }
  5.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Mi objetivo, con éste código, es poder calcular un dígito verificador.
El mismo se obtiene haciendo lo siguiente:
  1. como parámetro, recibo un string
  2. a ese string, supongamos como ejemplo el "0123456789", debo de asignarle una secuencia fija (1,3,5,7,9) las veces que sea necesario PERO el primero de ésta secuencia, sólo para el primer dígito. Es decir, para el caso que puse como ejemplo: "1357935793"
  3. multiplicar UNO en UNO, tanto el string del paso 1 (0123456789) con el obtenido en el paso 2 (1357935793)
  4. otros cálculos extras que llevan (finalmente) a dar con ESE bendito dígito verificador que necesito para luego concatenarlo con otro string pero éste último paso ya lo tengo resuelto :D


Ahora, estoy teniendo un problema al ejecutar el siguiente código:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2.  
  3. # una cadena cualquiera, puede variar la longitud de ésta
  4. $code = '123';
  5.  
  6. $length_code = length($code);
  7.  
  8. # esta es una secuencia que debo usar
  9. @sequence = ( 3, 5, 7, 9 );
  10. $i        = 0;
  11. $seq      = 0;
  12.  
  13. print 'la longitud del código es de: ', $length_code, "\n";    #3
  14.  
  15. while ( $i < $length_code ) {
  16.     if ( $i == '0' ) {
  17.         $head = substr( $code, 0, 1 );
  18.         print '$head: ', $head, "\n";
  19.     }
  20.     else {
  21.  
  22.         for ( $j = 1; $j < $length_code; $j++ ) {
  23.  
  24.             # print $length_code "\n";            # Si imprimo esto me tira el siguiente error -> print() on unopened filehandle 3 at test.pl line 25.
  25.  
  26.             $tail += substr( $code, $j, 1 ) * $sequence[$seq];
  27.             $seq++;
  28.             if ( $seq == 4 ) {
  29.                 $seq = 0;
  30.             }
  31.             print 'tail: ', $tail, "\n";
  32.         }
  33.  
  34.     }
  35.     $i++;
  36. }
  37. my $total = $head + $tail;             # sumo cabeza con cola
  38.  
  39. print 'total: ', $total, "\n";
  40.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


salida:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
la longitud del código es de: 3
$head: 1
print() on unopened filehandle 3 at test.pl line 25.
tail: 6
print() on unopened filehandle 3 at test.pl line 25.
tail: 21
print() on unopened filehandle 3 at test.pl line 25.
tail: 35
print() on unopened filehandle 3 at test.pl line 25.
tail: 62
total: 63
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Cuando total debería de ser: 22. Es decir, el $head:1 + $tail:21.

El problema se encuentra en el bucle for() porque como verán al querer imprimir la variable $length_code en la línea 25, me arroja error :?
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Re: Cambiar puntero en un array

Notapor explorer » 2012-09-29 19:10 @840

El operador '%' es el operador módulo: devuelve el resto de la división entera entre los dos argumentos.

Esto es muy útil cuando queremos que una variable recorra los valores entre 0 y otro valor.

Supongamos que queremos que una variable solo recorra los valores de 0 a 3. Entonces escribimos dentro del bucle:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $seq++;           # incrementamos la variable
  2. $seq = $seq % 4;  # calculamos el resto de la división de $seq entre 4
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Con este código tan sencillo, $seq solo tendrá los valores de 0 a 3 (cuando alcance el 4, 4/4=1, y resto=0, por lo que vuelve a valor 0).

El error del print es porque se te ha olvidado poner una coma entre $length_code y "\n";.

El por qué no sale bien la suma de control, es porque realizas un bucle for (líneas 22 y siguientes) dentro de un bucle while (línea 15). Estás recorriendo todos los caracteres por cada uno de los caracteres.

Esta es mi versión:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. my $secuencia = shift                           # leemos un argumento
  7.     or die "Uso: $0 <secuencia>\n";
  8.  
  9. my $i = 0;
  10. my @coeficientes = qw( 1 3 5 7 9 );
  11.  
  12. my $suma = 0;
  13.  
  14. for my $d (split //, $secuencia) {              # partimos la secuencia de dígitos
  15.  
  16.     $suma += $d  *  $coeficientes[ $i ];        # hacemos la suma
  17.  
  18.     $i++;                                       # siguiente coeficiente
  19.     $i = $i % @coeficientes;                    # volvemos a 0, si llegamos al final
  20.     $i = 1 if $i == 0;                          # evitamos ver el primer coeficiente de nuevo
  21. }
  22.  
  23. print "Longitud del código: ", length($secuencia), ". Total: $suma\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
explorer@joaquinferrero:~/Documentos/Desarrollo> perl kk.pl 0123456789
Longitud del código: 10. Total: 263
explorer@joaquinferrero:~/Documentos/Desarrollo> perl kk.pl 123
Longitud del código: 3. Total: 22
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Cambiar puntero en un array

Notapor reLlene » 2012-10-01 09:50 @451

¡¡Gracias por el tiempo, como siempre tan impecable, explorer!!

En principio, no me enteraba de TAN error garrafal a la hora de recorrer el bucle for() por CADA bucle while(); mira que estuve haciendo pruebas y ¡¡¡NO ME ENTERABAA!!! ¡ja,ja!

Ahora una duda.. Me remito a la línea 20 de tu código:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $i = 1 if $i == 0;         # evitamos ver el primer coeficiente de nuevo
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y pregunto: ¿Hay necesidad de ello? Me refiero a que no existe (o al menos yo no me entero, nuevamente xD ) el caso para que $i == 0 y mi fundamento es porque antes de declarar el bucle, se define a la variable en cero y una vez que entra al bucle se incrementa a éste antes de salir... ¿¿Estoy en lo correcto?? :shock:

¡Saludos!

P.d: ¡¡¡El uso del % me viene fantástico!!! :D
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Re: Cambiar puntero en un array

Notapor explorer » 2012-10-01 11:43 @530

El objetivo es conseguir que en la primera vuelta del bucle tengamos acceso a $coeficientes[0], ya que contiene el '1' que nos hace falta para la primera multiplicación.

Pero no nos hace falta en el resto de vueltas.

En el bucle, primero obtenemos el coeficiente, hacemos la multiplicación, y vamos acumulando.

Luego incrementamos $i para que apunte al siguiente coeficiente, que siempre deberá ir de '1' al valor máximo. No en '0', porque la primera vez que el bucle pasa por la línea 16, ya vale '0' (el valor conque fue definido en la línea 9).

La línea 20 se asegura de que la segunda y siguientes vueltas $i siempre empiece por '1' (con lo que vamos obteniendo el segundo elemento de @coeficientes).

Si tomas el papel del ordenador, y con un lápiz y papel vas poniendo los contenidos de las variables, quizás lo veas más claro.

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
$i:0, 1, 2, 3 ↴
      ↑   ⇜   ↵
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


¿Todo esto es necesario? Desde luego que sí si queremos hacer la suma conforme a lo que dice el problema. No es necesario si adoptamos otra estrategia, como la que tenías tú de sacar el primer valor a un $head, y sumarlo al resto del sumatorio del resto de la cadena.

Digamos que mi solución busca conseguir el menor número de líneas encontrando la fórmula matemática que más se ajuste al problema.

Eso no implica que sea la mejor solución... ni la más clara, por supuesto.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Cambiar puntero en un array

Notapor reLlene » 2012-10-01 12:33 @565

Más claro, imposible... :shock:

¡¡¡Muchas gracias, explorer!!!
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados