• Publicidad

Agrupar elementos procedentes de diferentes líneas

Perl aplicado a la bioinformática

Agrupar elementos procedentes de diferentes líneas

Notapor ptahotep » 2013-08-19 11:15 @510

Hola, tengo un problema, quizás muy básico, pero que no consigo resolver. Y estaba pensando que seguro que existe algún módulo para resolverlo fácilmente.

El problema es el siguiente. Tengo varias líneas con elementos separados por tabuladores:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
X       Y       Z       W
X1      Y1      Z1      W1
X2              Z2      W2
X3      Y2      Z3
X2              Z4      W2
X2              Z4      W3
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Los ficheros tienen varios megas, pero tienen el formato que muestro en el ejemplo. A veces no se repiten elementos, pero otras veces se repite el mismo elemento de una columna, como ocurre en las últimas filas. Cuando ocurre esto, quisiera agrupar líneas, de la siguiente forma (todo queda igual, excepto que las últimas líneas son unidas a la segunda):
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
X       Y       Z       W
X1      Y1      Z1      W1
X2              Z4,Z2   W3,W2
X3      Y2      Z3
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


¿Cómo lo veis? ¿Existe alguna forma fácil de hacerlo sin romperse la cabeza durante horas? Gracias.
ptahotep
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2013-07-26 13:21 @598

Publicidad

Re: Agrupar elementos procedentes de diferentes líneas

Notapor explorer » 2013-08-19 12:33 @564

Yo he encontrado una manera, aunque no sé si es muy complicada... consiste en ir leyendo el archivo, e ir guardando la información en una estructura tridimensional ;)
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;
  4.  
  5. my %datos;
  6.  
  7. open my $IN, '<', 'code_35386.txt';
  8.  
  9. my $cabecera = <$IN>;                                   # leemos la cabecera para
  10. my $numero_campos = 1 + ($cabecera =~ tr/\t/\t/);       # saber el número de columnas
  11. #say $numero_campos;
  12.  
  13. #$" = "|";
  14. while (<$IN>) {                                         # leemos el resto de líneas
  15.  
  16.     chomp;
  17.  
  18.     my @campos = split /\t/;
  19.  
  20. #    say "@campos";
  21.  
  22.     for (my $i = 1; $i < $numero_campos; $i++) {     # para todas las columnas posibles
  23.  
  24.         if (not defined $campos[$i]) {               # para el caso de columnas al final de la línea
  25.              $campos[$i] = '';                       # si no están definidas, las ponemos como cadenas vacías
  26.          }
  27.  
  28.         $datos{ $campos[0] }[$i]{$campos[$i]} = 1;   # guardamos la información
  29.     }
  30. }
  31.  
  32. close $IN;
  33.  
  34. #use Data::Dumper;
  35. #say Dumper \%datos;
  36.  
  37. print $cabecera;                                        # salida: sacamos la cabecera original
  38.  
  39. for my $key (sort keys %datos) {                                # para todas las claves encontradas
  40.  
  41.     my @fila = $key;                                            # vamos a construir la nueva línea
  42.  
  43.     for (my $i = 1; $i < $numero_campos; $i++) {                # para todas las columnas posibles
  44.  
  45.         push @fila, join(',', keys %{$datos{$key}[$i]});        # sacamos todos los valores unidos por ','
  46.     }
  47.  
  48.     say join "\t", @fila;                                       # sacamos toda la fila, uniendo las columnas con "\t"
  49. }
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
La estructura tridimensional tiene, en su primera dimensión, el valor de la primera columna, que suponemos que debe ser único (agrupar filas). La segunda dimensión es un índice que recorre el resto de columnas. Y la tercera dimensión es un hash, que recuerda qué valores han salido (según el valor de la primera columna y de la columna en que nos encontremos).

El uso de un array para las columnas nos facilita recorrerlas de forma consecutiva. Y el uso de un hash nos sirve tanto para recordar lo que ha salido, como para simplificar los datos repetidos.

El bucle de la 39 a la 49 puede reducirse a esto, aumentando un poco más la velocidad:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for my $key (sort keys %datos) {                                # para todas las claves encontradas
  2.  
  3.     # sacamos toda la fila, uniendo las columnas con "\t", y cada columna tiene sus valores unidos con ','
  4.     say join "\t", $key, map { join(',', keys %{$datos{$key}[$_]}) } 1 .. $numero_campos-1;
  5. }
Coloreado en 0.001 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: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Agrupar elementos procedentes de diferentes líneas

Notapor ptahotep » 2013-08-19 12:47 @574

Muchas gracias, lo probaré a ver qué tal. Lo veo bien, salvo que en la primera columna también suelen repetirse elementos.
ptahotep
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2013-07-26 13:21 @598

Re: Agrupar elementos procedentes de diferentes líneas

Notapor explorer » 2013-08-20 09:59 @458

Se supone que el objetivo era ese: agrupar líneas según el valor de la primera columna.
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 Bioinformática

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado