• Publicidad

Odd number of elements in hash assignment

Perl aplicado a la bioinformática

Odd number of elements in hash assignment

Notapor 3mgcantarero » 2017-11-26 06:58 @332

Buenos días.

Estoy intentando crear un módulo de perl que me recorra línea a línea un archivo Uniprot y que devuelva un hash multidimensional a partir del cual el programa principal me permita imprimir a la salida estándar los campos ID, DE, DT, OS y SQ de cada entrada del archivo uniprot.

Sé que hay alguna entrada a la que le falta alguno de los campos, y creo que esto es lo que está haciendo que cuando lanzo el programa principal obtenga el siguiente mensaje de error en la consola:

Odd number of elements in hash assignment at Intento1.pl line 28, <INFILE> line 2.

He intentado declarar las variables vacías antes de declarar el hash, pero eso tampoco me funciona... ¿Alguien me podría ayudar?

Muchas gracias.

Módulo
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. package Utils::Uniprot;
  2. use strict;
  3. use warnings;
  4.  
  5. use Exporter;
  6. our @ISA    = qw(Exporter);
  7. our @EXPORT = qw(ParseUniprot);
  8.  
  9. my $path;
  10. my $ID;
  11. my $DE;
  12. my $OS;
  13. my $DT;
  14. my $SQ;
  15.  
  16. sub ParseUniprot {
  17.     my ($path) = @_;
  18.     open( OUT, ">resultado.txt" );
  19.     my $linea;
  20.     open( INFILE, "$path" ) || die "$!:No se puede leer el archivo Uniprot_archea.txt\n\n";
  21.     while ( $linea = <INFILE> ) {
  22.         chomp $linea;
  23.         if ( $linea =~ /^ID\s{3}(\S+)\s+\S+\s+\d+/ ) {
  24.             $ID = $1;
  25.             next;
  26.         }
  27.         if ( $linea =~ /^DE\s+\w+/ ) {
  28.             $DE .= $linea;
  29.             $DE =~ s/DE//g;
  30.             next;
  31.         }
  32.         if ( $linea =~ /^DT\s{3}\S+\s\w{5}\s\w{7}\s\d+/ ) {
  33.             $DT = $linea;
  34.             $DT =~ s/DT//g;
  35.             next;
  36.         }
  37.         if ( $linea =~ /^OS\s{3}/ ) {
  38.             $OS .= $linea;
  39.             $OS =~ s/OS//;
  40.             next;
  41.         }
  42.         if ( $linea =~ /^\s{3}/ ) {
  43.             $SQ .= $linea;
  44.             $SQ =~ s/\s+//g;
  45.         }
  46.  
  47.         $DE = ();
  48.         $OS = ();
  49.         $DT = ();
  50.         $SQ = ();
  51.         my @list = ( $DE, $DT, $OS, $SQ );
  52.  
  53.         my %resultados;
  54.         $resultados{ID} = [@list];
  55.         return (%resultados) . "\n";
  56.     }
  57.     close OUT;
  58. }
  59. 1;
  60.  
Coloreado en 0.015 segundos, usando GeSHi 1.0.8.4


Programa principal
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. BEGIN{
  7.         use Getopt::Long;
  8.         die "You have and *old* version of Getopt::Long, please",
  9.             "update it asap!!\n"
  10.             unless Getopt::Long->VERSION>=2.5;
  11. }
  12.  
  13. use Getopt::Long;
  14. use lib '/home/alumno/Perl_modules/';
  15. use Utils::Uniprot;
  16.  
  17. my $path;
  18. my %info;
  19. my %resultados;
  20. my $dato;
  21.  
  22. GetOptions (
  23.                 "path=s"=>\$path,
  24.  
  25. );
  26.  
  27. if ($path) {
  28.         my %info=ParseUniprot($path);
  29.         foreach my $info (sort keys %resultados){
  30.              print $info{ID}[0]."\n";  
  31.              print $info{ID}[1]."\n";
  32.              print $info{ID}[2]."\n";
  33.              print $info{ID}[3]."\n";
  34.         }
  35. }
  36. else {
  37.         print "USAGE:: perl $0 -path=/home/alumno/asignatura_10/Semana4/Uniprot_archea.txt\n";
  38. }
Coloreado en 0.009 segundos, usando GeSHi 1.0.8.4
Última edición por explorer el 2017-11-26 07:54 @370, editado 1 vez en total
Razón: Formateado de código con perltidy; poner marcas Perl en el código;
3mgcantarero
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2017-11-12 04:41 @237

Publicidad

Re: Odd number of elements in hash assignment

Notapor explorer » 2017-11-26 08:58 @415

Es un error frecuente. El mensaje dice "Número impar de elementos en la asignación de un hash".

En el momento de asignar valores a un hash, se espera un número par de elementos. Recordar que un hash se compone de pares clave/valor.

En la línea 28 quieres recibir unos valores y guardarlo en el hash %info. Y resulta que está recibiendo un número impar.

Si hacemos una prueba en la línea de comandos, lo vemos más claro:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. > perl -w -MData::Dumper -e 'my %y = a(); print Dumper \%y; sub a { %x=(ID=>[("","","","")]); return (%x) . "\n" }'
  2. Odd number of elements in hash assignment at -e line 1.
  3. $VAR1 = {
  4.           '1
  5. ' => undef
  6.         };
Coloreado en 0.007 segundos, usando GeSHi 1.0.8.4

Aquí estoy reproduciendo el comportamiento del módulo y de tu programa, que está llamando a una subrutina a(), que define un hash %x, y luego hace el return igual a como lo tienes en tu módulo. Y pasa algo raro. Fíjate que en %y acaba recibiendo una cadena de texto "1\n", y saca el mismo mensaje de error.

El error está en el return. Tienes puesto:

return (%resultados) . "\n";

Lo que hace esa línea es reducir todo el hash a un único valor, y luego le concatena un retorno de carro. Y me parece que esto no es lo que quieres que devuelva la subrutina. Lo que quieres es que devuelva todo el hash, así que lo que hay que poner es

return %resultados;

Y ya obtenemos el resultado esperado:

Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. > perl -w -MData::Dumper -e 'my %y = a(); print Dumper \%y; sub a { %x=(ID=>[("","","","")]); return %x }'
  2. $VAR1 = {
  3.           'ID' => [
  4.                     '',
  5.                     '',
  6.                     '',
  7.                     ''
  8.                   ]
  9.         };
Coloreado en 0.008 segundos, usando GeSHi 1.0.8.4


Otros detalles curiosos del código:
En el módulo:
  • 18: abres un archivo, pero no escribes nada en él
  • 42: si $línea comienza con tres espacios en blanco, realiza una asignación a $SQ, y luego sigue por las líneas 47 y siguientes
  • 47: pone todas las variables definidas unas líneas antes, a nada (?)
  • 51: declara y define un array @list con el contenido de las variables, pero antes han sido limpiadas, así que está creando un array de 4 elementos vacíos
  • 54: estás guardando la lista en la clave 'ID', que es fija para todas las líneas leídas. ¿No será '$ID'?
En el programa:
  • 29: el hash $resultados nunca se ha definido, por lo que ese bucle nunca se ejecuta. Es posible que la línea 28 en realidad sea $resultados = ParseUniprot($path);
JF^D Perl Programming Language
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14102
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Odd number of elements in hash assignment

Notapor 3mgcantarero » 2017-11-26 11:49 @534

Hola.

Es cierto que he mandado un archivo que no es el definitivo y podían quedar cosas como el archivo .txt que abría y en el que no escribía nada. Ese archivo lo voy creando para ver qué voy recogiendo la información que necesito en cada variable.

Estoy bastante atascada con el tema del hash. Creo que no termino de entender muy bien cómo funciona y menos cuando se trata de un hash múltiple en el que hay que almacenar varios valores para varias claves y no consigo hacer que funcione y menos aún que el programa principal recoja el hash generado en el módulo para imprimir por la salida estándar el contenido...

Si me pudieras echar una mano, o indicar algún manual que me pudiera aclarar un poco...

Un saludo y muchas gracias.

Mónica.
3mgcantarero
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2017-11-12 04:41 @237

Re: Odd number of elements in hash assignment

Notapor explorer » 2017-11-26 19:46 @865

Hay otro detalle: fíjate que el return está metido dentro del bucle de lectura de líneas. Lo normal es que esté al final.

Y para pasar los %resultados al programa principal, te vale con el return %resultados que te puse.

Cuando quieras ver el contenido de una estructura más o menos compleja, puedes usar el módulo Data::Dumper, que viene incluida con tu Perl. Por ejemplo:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use strict;
  3. use warnings;
  4.  
  5. use Data::Dumper;
  6.  
  7. my %hash = (
  8.         clave1  => [ 1, 2, 3, 4 ],
  9.         clave2  => {
  10.                         a => 'A',
  11.                         b => 'B',
  12.         },
  13.         clave3  => [qw( hola adios )],
  14. );
  15.  
  16. print Dumper \%hash;
Coloreado en 0.007 segundos, usando GeSHi 1.0.8.4

Este programa genera esta salida:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
$VAR1 = {
          'clave2' => {
                        'a' => 'A',
                        'b' => 'B'
                      },
          'clave3' => [
                        'hola',
                        'adios'
                      ],
          'clave1' => [
                        1,
                        2,
                        3,
                        4
                      ]
        };
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Y ya ves que te muestra una estructura compleja almacena en %hash.
(Las claves salen desordenadas porque así las guardan los hashes).

Si quieres leer documentación, tienes la última documentación en
https://github.com/perldocES/perldoc-es ... translated

o un poco más bonita en
https://metacpan.org/release/POD2-ES

https://github.com/perldocES/perldoc-es ... erllol.pod te comenta cómo hacer estructuras de arrays de arrays.

El truco para hace estructuras complejas (en tu programa metes arrays como valores de un hash) es que debes usar referencias, que al fin y al cabo son valores escalares, por lo que se pueden guardar como valores del hash. Cuando haces

$resultados{ID} = [@list];

estás "desplegando" los valores almacenados en @list, agrupados con los corchetes creas un array anónimo, cuya referencia guardas en el hash %resultados, en la clave 'ID'. Si le haces un Dumper, sale

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
    $VAR1 = {
              'ID' => [
                        '',
                        '',
                        '',
                        ''
                      ]
            };
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

(no salen valores dentro del array, por lo que te comenté en el correo anterior).

Para aprender sobre referencias, está el documento perlref, pero se te puede hacer algo pesado.
https://github.com/perldocES/perldoc-es ... erlref.pod

Quizás más amigable sea perlreftut, que es un tutorial:
https://github.com/perldocES/perldoc-es ... reftut.pod

Toda esta documentación está en tu propio ordenador, que puedes ver con el comando perldoc perlreftut, pero en inglés. Si quieres verlo en castellano, debes instalarte el paquete POD2::ES, pero si quieres puedes verlas vía web, con los enlaces que te he pasado.

Para entender los hashes, también está perldata, pero es muy extensa. Busca por la palabra hash.
https://github.com/perldocES/perldoc-es ... rldata.pod

Lo básico es: los hashes almacenan pares clave/valor. Y las claves son únicas, por lo que solo se puede almacenar un valor para esa clave. Y los valores son siempre escalares (números, letras, cadenas de texto, referencias a otras estructuras).

Truco: hay código Perl para leer archivos Uniprot por Internet. Puedes mirarlos para inspirarte. Inténtalo. Si te atascas, vuelve por aquí y te daremos más pistas.
JF^D Perl Programming Language
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14102
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Bioinformática

¿Quién está conectado?

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