• Publicidad

Hamming distance

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

Hamming distance

Notapor Nuiter » 2021-08-06 12:33 @564

Hola buenas tardes, estoy intentando calcular la Distancia de Hamming entre dos cadenas de distinta longitud, y la verdad es que no lo consigo, tengo problemas en las líneas comentadas.

El código no está terminado, pero necesito que me funcione esa parte, para continuar.

¿Alguien podría decirme por qué no me funciona? Muchas gracias.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2.  
  3. use 5.010;
  4. use strict;
  5. use warnings;
  6.  
  7. my $name = 'Arturito, ';
  8. my $email= '[email protected], ';
  9. my $slacknick='@Nuiter, ';
  10. my $biostack='Genomics, DS, M&D Learning, ';
  11. my $twit_handle='@Nuiter_Qur, ';  
  12. my $arch = 'output.txt';
  13.  
  14. print '$slacknick:$twit_handle hd:', hd($slacknick, $twit_handle);  # mis problemas están de aquí
  15. sub hd
  16.         {length($_[ 0 ])-(($_[ 0 ])^($_[ 1 ])=~ tr[\0][\0] )}       # a aquí
  17.  
  18. my $output = $name.$email.$slacknick.$biostack.$twit_handle. ;
  19. say $output;
  20.  
  21. open(IN, '>', $arch) or die $!;
  22.  
  23. print IN $output
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Nuiter
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2019-06-11 17:52 @786

Publicidad

Re: Hamming distance

Notapor explorer » 2021-08-06 16:32 @730

Trabajar con cadenas de bits para hacer operaciones binarias con ellas, siempre ha sido un dolor de cabeza con Perl. Al menos hasta la versión 5.22.

Pero antes, un error sintáctico que he visto en el código (recuerda que con perl -c <programa.pl> el intérprete te avisa de estos errores): en la línea 18 la sentencia acaba con un '.' delante del ';' final. Ese punto sobra. O le falta algo después.

En la documentación de Perl, en el documento perlop, sección "Operadores de bit en cadenas" (en español), se comenta esta problemática sobre las cadenas de bits. Casi siempre, acababas yendo carácter por carácter para estar seguro.

En el foro de Bioinformática hay un ejemplo muy bonito de esta técnica, para buscar diferencias en proteínas (líneas 295 a 307).

Bueno, el caso es que hay que tener mucho cuidado con la notación. La siguiente solución me funciona en un Perl v5.18:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.18;
  3.  
  4. my $slacknick   = '@Nuiter, ';
  5. my $twit_handle = '@Nuiter_Qur, ';
  6.  
  7. print "[$slacknick][$twit_handle] HD:", hd($slacknick, $twit_handle), "\n";
  8.  
  9. sub hd {
  10.     my($x, $y) = @_;
  11.     my $xor             = "$x" ^ "$y";
  12.     my $l               = length $xor;
  13.     my $coincidencias   = $xor =~ tr[\0][\0];
  14.     my $res             = $l - $coincidencias;
  15.    
  16.     say "XOR: [$xor], longitud: ", $l;
  17.     say "Coincidencias: $coincidencias";
  18.     say "HD: $res";
  19.  
  20.     $res;
  21. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La salida es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
XOR: [       squr, ], longitud: 13
Coincidencias: 7
HD: 6
[@Nuiter, ][@Nuiter_Qur, ] HD:6
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

He dividido la ejecución en pasos, para detallarlos mejor.
En la línea 11 hacemos la operación Or-exclusivo, pero con los operandos entrecomillados dobles, como recomienda la documentación, para asegurarnos que se hace la operación entre cadenas de caracteres, y no haciendo la conversión a números, en caso de que alguno de los operandos lo sea.

En la línea 12 viene algo importante: lo que nos interesa es calcular el número de diferencias entre las dos cadenas, y eso se consigue sabiendo la longitud de la cadena más larga, menos el número de caracteres coincidentes en la misma posición. Podemos aprovechar el hecho de que la operación de Or-Exclusivo "rellena" con "\0" la cadena más corta, devolviendo una cadena de resultado tan larga como el más largo de los operandos. En el código anterior usabas la longitud del primer argumento, pero daba la casualidad de que era el más corto de los dos, así que la operación de cálculo de diferencias no daba el resultado correcto.

El resto de líneas hace las mismas operaciones que en tu código (longitud de la cadena, menos el número de $coincidencias).

En el resultado, en la terminal no vemos lo que hay delante de "squr, ", porque son bytes "\0", pero se pueden ver con un volcador hexadecimal, como por ejemplo hexdump -C:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
explorer@Arcanus:~/Documentos/Desarrollo > perl code_41484.pl |hexdump -C
00000000  58 4f 52 3a 20 5b 00 00  00 00 00 00 00 73 71 75  |XOR: [.......squ|
00000010  72 2c 20 5d 2c 20 6c 6f  6e 67 69 74 75 64 3a 20  |r, ], longitud: |
00000020  31 33 0a 43 6f 69 6e 63  69 64 65 6e 63 69 61 73  |13.Coincidencias|
00000030  3a 20 37 0a 48 44 3a 20  36 0a 5b 40 4e 75 69 74  |: 7.HD: 6.[@Nuit|
00000040  65 72 2c 20 5d 5b 40 4e  75 69 74 65 72 5f 51 75  |er, ][@Nuiter_Qu|
00000050  72 2c 20 5d 20 48 44 3a  36 0a                    |r, ] HD:6.|
0000005a
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
Ahí ves los byte "\0".

Por fortuna, como hemos dicho antes, Perl ha evolucionado y ya hay un mejor soporte para estas operaciones. A partir de Perl v5.22 hay un soporte experimental para la característica "bitwise" que añade operadores específicos para cadenas de bits. A partir de Perl v5.28 ya forma parte del lenguaje.

Entonces, el código queda un poco más ligero:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.28;
  3. use experimental 'signatures';
  4.  
  5. my $slacknick   = '@Nuiter, ';
  6. my $twit_handle = '@Nuiter_Qur, ';
  7.  
  8. say "[$slacknick][$twit_handle] HD:", hd($slacknick, $twit_handle);
  9.  
  10. sub hd ($x, $y) {
  11.     my $xor = $x ^. $y;
  12.     length($xor) - $xor =~ tr[\0][\0];
  13. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La salida es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
[@Nuiter, ][@Nuiter_Qur, ] HD:6
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Hemos añadido la característica (aún) experimental 'signatures' para acceder a los argumentos de la función, y en la operación de Or-exclusivo hemos usado el nuevo operador "^." para obligar a que la operación sea en cadenas de caracteres.

(Para el que no acabe de entender por qué sale un 6, es porque las cadenas difieren a partir de la "," en la octava posición -los primeros 7 caracteres son iguales-. La cadena más larga tiene 13 caracteres, así que la diferencia es 6).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Básico

¿Quién está conectado?

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